Разница между findAny () и findFirst () в Java 8

91

Я немного путают между Stream#findAny()и Stream#findFirst()из StreamAPI в Java 8.

Я понял, что оба будут возвращать первый совпавший элемент из потока, например, при использовании вместе с фильтром?

Итак, почему два метода для одной и той же задачи? Я что-то упускаю?

Мандип Раджпал
источник

Ответы:

94

Я понял, что оба будут возвращать первый совпавший элемент из потока, например, при использовании вместе с фильтром?

Это не правда. Согласно javadoc Stream#findAny():

Возвращает Optional<T>описание некоторого элемента потока или пустое значение, Optional<T>если поток пуст. Поведение этой операции явно недетерминировано; Вы можете выбрать любой элемент в потоке. Это сделано для обеспечения максимальной производительности при параллельных операциях;

while Stream.findFirst()вернет строгоOptional<T> описывающий первый элемент потока. У класса нет метода, значит, вы имели в виду .Stream.findOne().findFirst()

Константин Йовков
источник
Я до сих пор не понимаю, так что вы говорите, даже после того, как filterприменяется, findAnyможет вернуть любой элемент, в том числе , что не соответствует фильтр применяется?
Корай Тугай
@KorayTugay - Нет, после фильтра, какие бы оставшиеся элементы ни присутствовали, findAnyможет возвращаться любой элемент из этого (вроде) случайным образом, особенно при параллельных потоковых операциях
КришПрабакар
46

Нет, оба не вернут первый элемент Stream.

Из Stream.findAny()(выделено мной):

Возвращает Optionalописание некоторого элемента потока или пустое значение, Optionalесли поток пуст.

Это закорачивающая клемма.

Поведение этой операции явно недетерминировано; Вы можете выбрать любой элемент в потоке . Это сделано для обеспечения максимальной производительности при параллельных операциях; цена заключается в том, что несколько вызовов одного и того же источника могут не возвращать один и тот же результат. (Если желателен стабильный результат, используйте findFirst().)

Проще говоря, он может выбрать или не выбрать первый элемент Stream.

Я считаю, что с текущей реализацией, специфичной для Oracle, она вернет первый элемент в непараллельном конвейере. Однако в параллельном конвейере это не всегда, например, выполнение

System.out.println(IntStream.range(0, 100).parallel().findAny());

он вернулся, OptionalInt[50]когда я его запустил. Во всяком случае, вы не должны полагаться на это.

Тунаки
источник
17

findFirst возвращает первые элементы потока, но findAny может выбрать любой элемент в потоке.

List<String> lst1 = Arrays.asList("Jhonny", "David", "Jack", "Duke", "Jill","Dany","Julia","Jenish","Divya");
List<String> lst2 = Arrays.asList("Jhonny", "David", "Jack", "Duke", "Jill","Dany","Julia","Jenish","Divya");

Optional<String> findFirst = lst1.parallelStream().filter(s -> s.startsWith("D")).findFirst();
Optional<String> fidnAny = lst2.parallelStream().filter(s -> s.startsWith("J")).findAny();

System.out.println(findFirst.get()); //Always print David
System.out.println(fidnAny.get()); //Print Jack/Jill/Julia :behavior of this operation is explicitly nondeterministic
Амир
источник
2

в параллельном режиме findAnyне гарантируется порядок, ноfindFirst .

Я написал фрагмент кода, чтобы показать разницу, посетите его

Джиахут
источник
1

В потоках findFirst и findAny возвращают первый элемент и не выполняют остальные, но в parallelStream невозможно указать порядок, а parallelStream выполняет оставшуюся часть коллекции.

Справка

Время 1:25:00

эмон
источник
1

Скажу лишь, что остерегайтесь findFirst()И findAny()при использовании.

Как видно из их Javadoc ( здесь и здесь ), оба метода возвращают произвольный элемент из потока - если поток не имеет порядка встречи , и в этом случае findFirst()возвращается первый элемент, а findAny()вернет любой элемент.

Предположим, у нас есть заказ, listсостоящий из ISBN и имени КНИГИ. В качестве сценария посмотрите этот пример:

public class Solution {
   private Integer ISBN;
   private String BookName;

public Solution(int i, String string) {
    ISBN =i;
    BookName = string;
}
//getters and setters
}

public static void main(String[] args) {
        List<Solution> Library = Arrays.asList(new Solution(12,"Java in Action"),new Solution(13,"Java 8"),new Solution(15,"Java 8 Features"),new Solution(16,"Java in Action"));
 System.out.println(Library.stream()
        .map(p->p.getBookName())
        .sorted(Comparator.reverseOrder())
        .findFirst());
    }

Выход :Optional[Java in Action]

Могут быть сценарии, когда название книги совпадает, но номера ISBN разные, в этом случае сортировка и поиск книги могут быть очень похожи findAny()и дадут неверный результат. Подумайте о сценарии, в котором 5 книг названы «Справочник по Java», но имеют разные номера ISBN, и findFirst()книга по названию будет иметь такой же результат findAny().

Подумайте о сценарии, в котором:

 ISBN    Name Of book
+-----+------------------+
| 100 | Java-8 in Action |
+-----+------------------+
| 101 | Java-8 in Action |
+-----+------------------+
| 102 | Java-8 in Action |
+-----+------------------+
| 103 | Java-8 in Action |
+-----+------------------+
| 104 | Java-8 in Action |
+-----+------------------+

здесь findFirst () и findAny () дадут одинаковый результат, даже если они отсортированы по BookByName.

Подробная статья:

Вишва Ратна
источник
-1

Когда Streamнеупорядочено, findFirst()и findAny()такие же. Но когда Streamзаказывают, findAny()будет лучше.

logbasex
источник
Это неверно. Ни один из этих методов не «лучше», потому что их поведение и варианты использования совершенно разные. Кроме того, что вы имеете в виду под Stream«заказанным»? Он всегда упорядочен (операции выполняются в заданном Streamпорядке каждый раз, когда он не распараллеливается), но, возможно, не сортируется пользователем.
Jezor