Різниця між findAny () та findFirst () у Java 8


90

Я трохи плутають між Stream#findAny()і Stream#findFirst()з StreamAPI в Java 8.

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

Отже, чому два методи для одного завдання? Мені чогось не вистачає?

Відповіді:


92

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

Це не правда. Відповідно до javadoc Stream#findAny():

Повертає Optional<T>опис деякого елемента потоку або порожнього, Optional<T>якщо потік порожній. Поведінка цієї операції явно недетерміноване; безкоштовно вибрати будь-який елемент у потоці. Це дозволяє забезпечити максимальну продуктивність при паралельних операціях;

while Stream.findFirst()поверне Optional<T>описуючий строго перший елемент потоку. У Streamкласі немає .findOne()методу, тож, мабуть, ви мали на увазі .findFirst().


Я все ще не розумію, тому те, що ви говорите, навіть після того, filterяк застосовано, findAnyможе повернути будь-який елемент, включаючи той, що не відповідає застосованому фільтру?
Корай Тугай

@KorayTugay - Ні, після того, як фільтр, які б решта елементи не були, findAnyможе повернути будь-який елемент із нього у (начебто) випадковому, особливо при паралельних операціях потоку
KrishPrabakar

46

Ні, обидва не повернуть перший елемент потоку.

З Stream.findAny()(наголос мій):

Повертає Optionalопис деякого елемента потоку або порожнього, Optionalякщо потік порожній.

Це коротке замикання терміналу.

Поведінка цієї операції явно недетерміноване; безкоштовно вибрати будь-який елемент у потоці . Це дозволяє забезпечити максимальну продуктивність при паралельних операціях; вартість полягає в тому, що багаторазові виклики в одному джерелі можуть не повернути однаковий результат. (Якщо бажаний стабільний результат, використовуйте findFirst()замість нього.)

Тож простіше кажучи, він може або не може вибрати перший елемент Потоку.

З поточною реалізацією Oracle, я вважаю, що вона поверне перший елемент у непаралельному конвеєрі. Однак у паралельному конвеєрі це не завжди (виконати, наприклад System.out.println(IntStream.range(0, 100).parallel().findAny());, повернулося, OptionalInt[50]коли я його запустив). У будь-якому випадку, ви не повинні на це покладатися.


16

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 повертають перший елемент і не виконують решту, але паралельно Stream не можна сказати порядок, а паралельний потік виконує решту колекції.

Довідково

Час 1:25:00


1

Я просто скажу, що остерігайтеся findFirst()І findAny()під час використання.

Починаючи з їх Javadoc ( тут і тут ), обидва методи повертають довільний елемент з потоку - якщо потік не має порядку зустрічі , в цьому випадку findFirst()повертає перший елемент, а findAny()поверне будь-який елемент.

Припустимо, у нас є спеціальний номер listISBN та назва КНИГИ. Для сценарію подивіться на цей приклад:

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в однаковому порядку кожного разу, коли це не паралельно), але, можливо, не сортується користувачем.
Єзор
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.