forEach vs forEachOrdered in Java 8 Stream

83

Ich verstehe, dass diese Methoden die Ausführungsreihenfolge unterscheiden, aber in all meinen Tests kann ich keine unterschiedliche Ausführungsreihenfolge erreichen.

Beispiel:

System.out.println("forEach Demo");
Stream.of("AAA","BBB","CCC").forEach(s->System.out.println("Output:"+s));
System.out.println("forEachOrdered Demo");
Stream.of("AAA","BBB","CCC").forEachOrdered(s->System.out.println("Output:"+s));

Ausgabe:

forEach Demo
Output:AAA
Output:BBB
Output:CCC
forEachOrdered Demo
Output:AAA
Output:BBB
Output:CCC

Bitte geben Sie Beispiele an, wenn 2 Methoden unterschiedliche Ausgaben erzeugen.

gstackoverflow
quelle
Versuchen Sie es vielleicht mit parallelen Streams.
Pshemo
@Pshemo ist es nur möglich Option?
gstackoverflow
5
Eine nicht spezifizierte Bestellung bedeutet nicht, dass die Bestellung garantiert anders ist. Es bedeutet nur nicht spezifiziert , was immer die Möglichkeit impliziert, der Begegnungsreihenfolge zu entsprechen. Es gibt keine eingebaute Zufallsfunktion.
Holger

Antworten:

84
Stream.of("AAA","BBB","CCC").parallel().forEach(s->System.out.println("Output:"+s));
Stream.of("AAA","BBB","CCC").parallel().forEachOrdered(s->System.out.println("Output:"+s));

Die zweite Zeile wird immer ausgegeben

Output:AAA
Output:BBB
Output:CCC

Der erste ist nicht garantiert, da die Bestellung nicht eingehalten wird. forEachOrderedverarbeitet die Elemente des Streams in der von seiner Quelle angegebenen Reihenfolge, unabhängig davon, ob der Stream sequentiell oder parallel ist.

Zitat aus forEachJavadoc:

Das Verhalten dieser Operation ist explizit nicht deterministisch. Bei parallelen Stream-Pipelines garantiert diese Operation nicht, dass die Aufeinanderreihenfolge des Streams eingehalten wird, da dies den Vorteil der Parallelität beeinträchtigen würde.

Wenn der forEachOrderedJavadoc sagt (Schwerpunkt Mine):

Führt eine Aktion für jedes Element dieses Streams in der Begegnungsreihenfolge des Streams aus, wenn der Stream eine definierte Begegnungsreihenfolge hat.

Tunaki
quelle
6
Ja, du hast recht. Ist es nur für parallelStreams möglich?
gstackoverflow
6
Selbst wenn es momentan nur für parallele Streams gelten würde - und ich sage es nicht -, könnte es in Zukunft noch brechen, wenn einige Zwischenschritte optimiert werden, um ungeordnete Streams zu nutzen, z. B. könnte eine Sortierung einen instabilen Algorithmus verwenden, wenn Der Stream ist ungeordnet.
The8472
1
Es macht also keinen Sinn, forEachOrderedmit zu verwenden parallel?
Bhushan
3
@ BhushanPatil Ja, das ist richtig. stackoverflow.com/questions/47336825/…
Sagar
1
Wenn Sie forEachOrdered verwenden, werden die Elemente nach Reihenfolge verarbeitet. Wenn Sie dann parallele Streams verwenden, verlieren Sie die Vorteile der Parallelität. Bitte vorschlagen.
Deepak
30

Obwohl forEachkürzer und hübscher aussieht, würde ich empfehlen, sie forEachOrderedan jedem Ort zu verwenden, an dem die Reihenfolge wichtig ist, um dies explizit anzugeben. Für sequentielle Streams forEachscheint das die Reihenfolge zu respektieren und sogar den internen Code der Stream-API zu verwenden forEach (für Streams, von denen bekannt ist, dass sie sequentiell sind), wo es semantisch notwendig ist, sie zu verwenden forEachOrdered! Trotzdem können Sie später entscheiden, Ihren Stream auf parallel zu ändern, und Ihr Code wird beschädigt. Auch wenn Sie forEachOrderedden Leser Ihres Codes verwenden, wird die Meldung angezeigt: "Hier ist die Reihenfolge wichtig". So wird Ihr Code besser dokumentiert.

Beachten Sie auch, dass für parallele Streams diese forEachnicht nur in nicht deterministischer Reihenfolge ausgeführt werden, sondern dass Sie sie auch gleichzeitig in verschiedenen Threads für verschiedene Elemente ausführen lassen können (was mit nicht möglich istforEachOrdered ).

Schließlich sind beide forEach/ forEachOrderedselten nützlich. In den meisten Fällen müssen Sie tatsächlich ein Ergebnis erzielen, nicht nur eine Nebenwirkung. Daher mögen reduceoder collectsollten Operationen besser geeignet sein. Das Ausdrücken eines von Natur aus reduzierenden Betriebs über forEachwird normalerweise als schlechter Stil angesehen.

Tagir Valeev
quelle
7
"Schließlich sind beide forEach / forEachOrdered selten nützlich". Ich könnte nicht mehr zustimmen. Es scheint, dass diese Methoden überstrapaziert sind.
Tunaki
Danke für die Antwort. aber es ist kein reales Beispiel. Ich lerne gerade Java 8
Gstackoverflow
Warum ist es semantisch notwendig, forEachOrdereddiesen Code zu verwenden?
RealSkeptic
1
@ RealSkeptic, es ist ein benutzerdefinierter Stream (übergeben an flatMap). Es kann bestellt werden, daher muss es in derselben Reihenfolge in den resultierenden Stream gestellt werden.
Tagir Valeev
2
@ RealSkeptic, du bist der echte Skeptiker! Stream.of("a", "b", "c").flatMap(s -> Stream.of("1", "2", "3").map(s::concat)).spliterator().hasCharacteristics(Spliterator.ORDERED)gibt true zurück, daher muss die Reihenfolge für den resultierenden Stream bestimmt werden. Wenn Sie der Meinung sind, dass die JDK-Dokumentation dies ausdrücklich erwähnen sollte, können Sie einen Fehler einreichen.
Tagir Valeev
14

forEach()Methode führt eine Aktion für jedes Element dieses Streams aus. Bei parallelen Streams garantiert diese Operation nicht, dass die Reihenfolge des Streams beibehalten wird.

forEachOrdered() Die Methode führt für jedes Element dieses Streams eine Aktion aus, um sicherzustellen, dass jedes Element in der Reihenfolge der Begegnung für Streams mit einer definierten Reihenfolge der Begegnung verarbeitet wird.

Nehmen Sie das folgende Beispiel:

    String str = "sushil mittal";
    System.out.println("****forEach without using parallel****");
    str.chars().forEach(s -> System.out.print((char) s));
    System.out.println("\n****forEach with using parallel****");

    str.chars().parallel().forEach(s -> System.out.print((char) s));
    System.out.println("\n****forEachOrdered with using parallel****");

    str.chars().parallel().forEachOrdered(s -> System.out.print((char) s));

Ausgabe:

****forEach without using parallel****

sushil mittal

****forEach with using parallel****

mihul issltat

****forEachOrdered with using parallel****

sushil mittal
Sushil Mittal
quelle