2016-04-19 4 views
9

Хотя я подозреваю, что ответ «Это не указано» ...Как StreamMax() обрабатывает равенство?

Если есть несколько «Величайшие/низкие» элементов в Stream которых Comparator перешла к max или min методам считает равной (возвращает 0) , будет ли он указан где-нибудь, какой элемент будет найден?

+5

Похоже, что не определено поведение. –

+3

Я бы предположил, что это зависит от базовой коллекции. – munyengm

+2

Боковой вопрос: почему это имеет значение? – Tunaki

ответ

3

Действительно трудно вывести определенное утверждение только из документации. Если мы попытаемся сделать вывод из общего описания процесса «Сокращения» и подобных намеков на документацию, всегда будет ощущение, что мы, возможно, слишком много интерпретируем.

Однако, есть explicit statement regarding this matter от Brian Goetz кто довольно авторитет относительно потока API:

Если поток упорядочен (например, потоки, вы получаете из массива или списка), он возвращает первый элемент, который максимален в случае нескольких максимальных элементов; только если поток неупорядочен, ему разрешено выбирать произвольный элемент.

Жаль, что такое явное заявление не сделано прямо в документации Stream.max, но, по крайней мере, это в соответствии с нашим опытом и знаниями реализации (those of us who looked at the source code). И не забывать практические соображения, так как легко сказать «выбрать любой, а не первый» через unordered().max(comparator) с текущим положением дел, чем сказать «выбрать сначала, а не любой», если бы max было разрешено выбирать произвольный элемент в первую очередь ,

+2

Я думаю, что явный оператор не стоит слишком много, потому что есть сторонние реализации «Потоков», не контролируемые разработчиками JDK. И если javadocs не ограничивают эти реализации, тогда они могут свободно обрабатывать этот случай, но они хотят. – the8472

+2

@ the8472: действительно? Назовите хотя бы один ... – Holger

+2

@ the8472: обратите внимание, что это утверждение не стоит в пустом пространстве. Как уже было сказано в ответе, есть * несколько аспектов документации, позволяющих сделать такой вывод; это явное утверждение является просто хорошим доказательством того, что мы здесь не слишком интерпретируем. – Holger

4

После прочтения исходного кода, я думаю, должен быть первый величайший элемент, который будет найден в соответствии с порядком сбора. Мы можем проверить исходный код Stream.max(Comparator<? super T> comparator), класс реализации является ReferencePipeline.max

@Override 
    public final Optional<P_OUT> max(Comparator<? super P_OUT> comparator) { 
     return reduce(BinaryOperator.maxBy(comparator)); 
    } 

, что вы можете видеть, когда вы вызываете Stream.max, вы имеете в виду вызвать Stream.reduce(BinaryOperator<P_OUT> accumulator)

И посмотрите на исходный код из BinaryOperator.maxBy(comparator)

public static <T> BinaryOperator<T> maxBy(Comparator<? super T> comparator) { 
     Objects.requireNonNull(comparator); 
     return (a, b) -> comparator.compare(a, b) >= 0 ? a : b; 
    } 

это ясно, когда a равна b, она возвращает a. Поэтому, когда в потоке есть несколько «наибольших/самых низких» элементов, элемент «наибольший/самый низкий» должен быть первым «самым большим/самым низким» элементом в соответствии с порядком сбора

Приведен пример, ваша рекомендация.

 List<Student> list = Arrays.asList(new Student("s1", 1), new Student("s2", 5), new Student("s3", 3), new Student("s4", 5)); 
     // it should be student of 's2' 
     list.stream().max(Comparator.comparing(Student::getScore)); 
     // it should be student of 's4' 
     list.stream().reduce((a, b) -> Comparator.comparing(Student::getScore).compare(a, b) > 0 ? a : b); 
+2

Это действительно зависит от упорядочения потока. Больше информации здесь http://stackoverflow.com/a/29218074/1743880 – Tunaki

+1

@Tunaki: Спасибо Tunaki, я многому учусь. :) – Tony

+4

Источник является информативным, но не нормативным. Вы не можете полагаться на вещи, если они не являются частью документации. – the8472

Смежные вопросы