Разница между 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


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()будет лучше.


Это неверно. Ни один из этих методов не «лучше», потому что их поведение и варианты использования совершенно разные. Кроме того, что вы имеете в виду под Stream«заказанным»? Он всегда упорядочен (операции выполняются в заданном Streamпорядке каждый раз, когда он не распараллеливается), но, возможно, не сортируется пользователем.
— Jezor
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.