Różnica między findAny () i findFirst () w Javie 8


90

Jestem trochę zdezorientowany między Stream#findAny()i Stream#findFirst()z StreamAPI w Javie 8.

Zrozumiałem, że oba zwrócą pierwszy dopasowany element ze strumienia, na przykład, gdy zostaną użyte w połączeniu z filtrem?

Dlaczego więc dwie metody do tego samego zadania? Czy coś mi brakuje?

Odpowiedzi:


92

Zrozumiałem, że oba zwrócą pierwszy dopasowany element ze strumienia, na przykład, gdy zostaną użyte w połączeniu z filtrem?

To nieprawda. Według javadoc Stream#findAny():

Zwraca Optional<T>opisując jakiś element strumienia lub pusty Optional<T>, jeśli strumień jest pusty. Zachowanie tej operacji jest wyraźnie niedeterministyczne; można wybrać dowolny element w strumieniu. Ma to na celu zapewnienie maksymalnej wydajności w operacjach równoległych;

while Stream.findFirst()zwróci Optional<T>opis ściśle pierwszego elementu strumienia. StreamKlasa nie ma .findOne()metody, więc przypuszczam, że masz na myśli .findFirst().


Nadal nie rozumiem, więc mówisz, że nawet po filterzastosowaniu a, czy findAnymożesz zwrócić dowolny element, w tym ten, który nie pasuje do zastosowanego filtra?
Koray Tugay

@KorayTugay - Nie, po filtrze, jakiekolwiek pozostałe elementy są obecne, findAnymoże zwrócić dowolny element z tego (w pewnym sensie) losowo, szczególnie w operacjach równoległego strumienia
KrishPrabakar

46

Nie, oba nie zwrócą pierwszego elementu strumienia.

Od Stream.findAny()(wyróżnienie moje):

Zwraca Optionalopisujący element strumienia lub pusty, Optionaljeśli strumień jest pusty.

Jest to operacja polegająca na zwarciu terminala.

Zachowanie tej operacji jest wyraźnie niedeterministyczne; można wybrać dowolny element w strumieniu . Ma to na celu zapewnienie maksymalnej wydajności w operacjach równoległych; Koszt jest taki, że wielokrotne wywołania z tego samego źródła mogą nie zwrócić tego samego wyniku. (Jeśli chcesz uzyskać stabilny wynik, użyj findFirst()zamiast tego).

Mówiąc prościej, może wybrać pierwszy element Strumienia, ale nie musi.

Uważam, że przy obecnej implementacji specyficznej dla Oracle zwróci ona pierwszy element w potoku nierównoległym. Jednak w potoku równoległym nie zawsze (na przykład wykonaj System.out.println(IntStream.range(0, 100).parallel().findAny());, zwrócił, OptionalInt[50]gdy go uruchomiłem). Tak czy inaczej, trzeba nie na tym polegać.


16

findFirst zwraca pierwsze elementy strumienia, ale findAny może wybrać dowolny element w strumieniu.

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

w trybie równoległym findAnynie gwarantuje porządku, ale findFirsttak.

Napisałem fragment kodu, aby pokazać różnicę, odwiedź go


1

W strumieniu findFirst i findAny zwracają pierwszy element i nie wykonują reszty, ale w parallelStream nie można podać kolejności, a parallelStream wykonuje pozostałą część kolekcji.

Odniesienie

Czas 1:25:00


1

Powiem tylko, że uważaj na findFirst()i findAny()podczas używania.

Począwszy od ich Javadoc ( tutaj i tutaj ), obie metody zwracają dowolny element ze strumienia - chyba że strumień ma kolejność spotkań , w takim przypadku findFirst()zwraca pierwszy element while findAny()zwróci dowolny element.

Załóżmy, że mamy niestandardowy listnumer ISBN i nazwę BOOK. Aby zobaczyć scenariusz, spójrz na ten przykład:

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());
    }

Wyjście :Optional[Java in Action]

Mogą istnieć scenariusze, w których nazwa książki jest taka sama, ale numery ISBN są różne, w takim przypadku sortowanie i znajdowanie książki może być bardzo podobne do findAny()i da błędny wynik. Pomyśl o scenariuszu, w którym 5 książek nosi nazwę „Referencje Java”, ale mają różne numery ISBN, a findFirst()książka według nazwy da taki sam wynik jak findAny().

Pomyśl o scenariuszu, w którym:

 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 |
+-----+------------------+

tutaj findFirst () i findAny () dadzą ten sam wynik, nawet jeśli zostaną posortowane według BookByName.

Szczegółowy artykuł:


-1

Kiedy Streamjest nieuporządkowany findFirst()i findAny()są takie same. Ale kiedy Streamzostanie zamówiony, findAny()będzie lepiej.


To jest niepoprawne. Żadna z tych metod nie jest „lepsza”, ponieważ ich zachowania i przypadki użycia są zupełnie inne. Co masz na myśli mówiąc o Streamistocie „zamówionej”? Jest zawsze uporządkowany (operacje są wykonywane w podanej Streamkolejności za każdym razem, gdy nie jest zrównoleglony), ale być może nie jest sortowany przez użytkownika.
Jezor
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.