Wie peek () und allMatch () in der Java 8 Stream API zusammenarbeiten

10

Ich habe ein Quiz über die Java 8 Stream API der Peek-Methode wie folgt gefunden

Arrays.asList("Fred", "Jim", "Sheila")
      .stream()
      .peek(System.out::println)
      .allMatch(s -> s.startsWith("F"));

Die Ausgabe ist

Fred
Jim

Ich bin verwirrt, wie dieser Stream funktioniert? Mein erwartetes Ergebnis sollte sein

Fred
Jim
Sheila

Die peek () -Methode ist eine Zwischenoperation und verarbeitet jedes Element in Stream. Kann mir das jemand erklären.

Barcelona
quelle

Antworten:

10

Es ist eine Stream-Optimierung, die als Kurzschluss bekannt ist. Im Wesentlichen wird allMatchverhindert , dass unnötige Zwischenoperationen im Stream ausgeführt werden, da es keinen Sinn macht, diese auszuführen, wenn das Endergebnis bekannt ist.

Es ist, als ob dies passiert wäre:

take"Fred"
peek("Fred")
evaluate("Fred".startsWith("F"))
decide whether the result of allMatch() is known for sure: Not yet

take"Jim"
peek("Jim")
evaluate("Jim".startsWith("F"))
decide whether the result of allMatch() is known for sure: Yes

Wenn "Jim".startsWith("F")ausgewertet wird, ist das Ergebnis von mit allMatch(s -> s.startsWith("F"))Sicherheit bekannt. Es spielt keine Rolle, welche Werte danach in die Pipeline kommen "Jim", wir wissen, dass alle Werte, die mit "F" beginnen, falsch sind

Dies ist nicht spezifisch für die peek/ allMatch-Kombination, es gibt mehrere Zwischen- und Endkurzschlussvorgänge. java.util.streamDer Dokumentstatus des Pakets :

Ferner werden einige Operationen als Kurzschlussoperationen angesehen. Eine Zwischenoperation ist kurzgeschlossen, wenn sie bei unendlicher Eingabe einen endlichen Strom erzeugen kann. Eine Terminaloperation ist kurzgeschlossen, wenn sie bei unendlicher Eingabe in endlicher Zeit beendet werden kann. Ein Kurzschlussbetrieb in der Pipeline ist eine notwendige, aber nicht ausreichende Bedingung, damit die Verarbeitung eines unendlichen Stroms in endlicher Zeit normal endet.

Erweitern Sie dies auf endliche Streams, und Kurzschlussoperationen verhindern die Ausführung unnötiger Pipeline-Schritte, wie im Fall Ihres Beispiels.

ernest_k
quelle
5
Arrays.asList("Fred", "Jim", "Sheila")
      .stream()
      .peek(System.out::println)
      .allMatch(s -> s.startsWith("F"));
  • Zum ersten Mal durch, Fredwird gedruckt. Es passt so
  • Das zweite Mal durch Jimwird gedruckt. Es stimmt nicht überein, daher wird allMatch beendet, weil "Alle stimmten nicht überein".
  • Der letzte Artikel wurde also nicht aus dem Stream verbraucht.
WJS
quelle
3

In den Dokumenten für die peekMethode heißt es (Hervorhebung von mir):

Gibt einen Stream zurück, der aus den Elementen dieses Streams besteht, und führt zusätzlich die bereitgestellte Aktion für jedes Element aus, wenn Elemente aus dem resultierenden Stream verbraucht werden .

In diesem Fall wird peekdies nicht angezeigt, "Sheila"da dieser Wert nicht aus dem Stream verwendet wird. Sobald "Jim"verbraucht wurde, ist das Ergebnis von .allMatch(s -> s.startsWith("F"))bereits bekannt false, sodass keine weiteren Elemente aus dem Stream verbraucht werden müssen.

kaya3
quelle
1

Gemäß Java Doc Of allMatch ():

Gibt zurück, ob alle Elemente dieses Streams mit dem angegebenen Prädikat übereinstimmen. Möglicherweise wird das Prädikat nicht für alle Elemente ausgewertet, wenn dies zur Ermittlung des Ergebnisses nicht erforderlich ist. Wenn der Stream leer ist, wird {@code true} zurückgegeben und das Prädikat wird nicht ausgewertet.

@apiNote

Diese Methode bewertet die universelle Quantifizierung des Prädikats über die Elemente des Stroms (für alle x P (x)). Wenn der Strom leer ist, wird die Quantifizierung als leer erfüllt bezeichnet und ist immer {@code true} (unabhängig von P (x)).

Prädikat für Elemente dieses Streams @return {@code true}, wenn entweder alle Elemente des Streams mit dem angegebenen Prädikat übereinstimmen oder der Stream leer ist, andernfalls {@code false}

In Ihrem Fall:

1-

p(x) : s -> s.startsWith("F")

X : "Fred"

result : X P(X) = true

2-

p(x) : s -> s.startsWith("F")

X : "Jim"

result : X P(X) = false

Es findet keine weitere Auswertung statt, da XP (X) = false ist

boolean result = Arrays.asList("Fred", "Finda", "Fish")
            .stream()
            .peek(System.out::println)
            .allMatch(s -> s.startsWith("F"));
    System.out.println("Result "+result);

Ausgabe ist:

Fred
Finda
Fish
Result true

Hier wird der Stream vollständig verarbeitet, da xP (x) = true von jedem Element ist

Sandeep Tiwari
quelle