wake-up-neo.com

Unterschied zwischen findAny () und findFirst () in Java 8

Ich bin wenig verwirrt zwischen Stream#findAny() und Stream#findFirst() der Stream-API in Java 8.

Was ich verstanden habe ist, dass beide das erste übereinstimmende Element aus dem Stream zurückgeben, zum Beispiel in Verbindung mit einem Filter?

Warum also zwei Methoden für dieselbe Aufgabe? Fehlt mir etwas?

51
Mandeep Rajpal

Was ich verstanden habe ist, dass beide das erste übereinstimmende Element zurückgeben aus dem Stream, zum Beispiel in Verbindung mit einem Filter?

Das ist nicht wahr. Nach dem Javadoc gilt Stream#findAny() :

Gibt ein Optional<T>-beschreibendes some -Element des Streams oder ein leeres .__ zurück. Optional<T> wenn der Stream leer ist . Das Verhalten dieser Operation ist explizit nicht deterministisch. es ist frei, ein beliebiges Element im Stream auszuwählen. Dies ermöglicht maximale Leistung im Parallelbetrieb.

während Stream.findFirst() einen Optional<T> zurückgibt, der streng das erste Element des Streams beschreibt. Die Stream-Klasse hat keine .findOne() -Methode, also haben Sie vermutlich .findFirst() gemeint.

59

Nein, beide geben nicht das erste Element des Streams zurück.

Von Stream.findAny() (Hervorhebung meiner):

Gibt ein Optional zurück, das ein Element des Streams beschreibt, oder ein leeres Optional, wenn der Stream leer ist.

Dies ist eine Kurzschlussklemmenoperation.

Das Verhalten dieser Operation ist ausdrücklich nicht deterministisch. es ist frei ein Element im Stream auszuwählen. Dies soll maximale Leistung im Parallelbetrieb ermöglichen; Die Kosten sind, dass mehrere Aufrufe auf derselben Quelle möglicherweise nicht dasselbe Ergebnis zurückgeben. (Wenn ein stabiles Ergebnis gewünscht wird, verwenden Sie stattdessen findFirst().)

Einfacher ausgedrückt kann es das erste Element des Streams auswählen oder auch nicht.

Ich glaube, dass mit der aktuellen Oracle-spezifischen Implementierung das erste Element in einer nicht parallelen Pipeline zurückgegeben wird. In einer parallelen Pipeline wird dies jedoch nicht immer der Fall sein (führen Sie zum Beispiel System.out.println(IntStream.range(0, 100).parallel().findAny()); aus, es wurde OptionalInt[50] Zurückgegeben, als ich es ausgeführt habe). Wie auch immer, darauf müssen Sie nicht vertrauen.

36
Tunaki

findFirst gibt die ersten Elemente des Streams zurück, aber findAny kann jedes Element im Stream auswählen. 

        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
3
Amir

im Parallelmodus garantiert die findAny keine Reihenfolge, die findFirst jedoch.

Ich habe ein Codeausschnitt geschrieben, um den Unterschied zu zeigen, besuchen Sie es

1
jiahut

Im Stream findFirst und findAny geben Sie das erste Element zurück und führen Sie den Rest nicht aus. In ParallelStream ist es jedoch nicht zulässig, die Reihenfolge anzugeben, und ParallelStream führt den Rest der Collection aus.

Referenz

Zeit 1:25:00

0
emon

Ich werde nur sagen, dass Sie sich vor findFirst() und findAny() während der Benutzung hüten.

Von ihrem Javadoc ( hier und hier ) geben beide Methoden ein beliebiges Element aus dem Stream zurück - es sei denn, der Stream hat ein Begegnungsreihenfolge. In diesem Fall gibt findFirst() das erste Element zurück Während findAny() ein Element zurückgibt.

Angenommen, wir haben eine benutzerdefinierte list, bestehend aus ISBN und BOOK-Namen. Für ein Szenario schauen Sie sich dieses Beispiel an:

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

Ausgabe: Optional[Java in Action]

Es kann Szenarien geben, in denen der Buchname gleich ist, die ISBN-Nummern jedoch unterschiedlich sind. In diesem Fall kann das Sortieren und Finden des Buchs findAny() sehr ähnlich sein und falsche Ergebnisse ergeben. Stellen Sie sich ein Szenario vor, in dem 5 Bücher "Java Reference" genannt werden, aber unterschiedliche ISBN-Nummern haben. Das findFirst()-Buch nach Namen führt zu demselben Ergebnis wie findAny().

Denken Sie an ein Szenario, in dem:

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

hier findFirst () und findAny () liefern dasselbe Ergebnis, auch wenn nach BookByName sortiert.

Ausführlicher Artikel: 

0
Common Man