forEach vs forEachOrdered in Java 8 Stream


87

Capisco che questi metodi differiscono nell'ordine di esecuzione ma in tutti i miei test non riesco a ottenere una diversa esecuzione degli ordini.

Esempio:

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

Produzione:

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

Fornisci esempi quando 2 metodi produrranno output diversi.


Prova forse con flussi paralleli.
Pshemo

@ Pshemo è l'unica opzione possibile?
gstackoverflow

5
Un ordine non specificato non implica "garantito un ordine diverso". Significa solo non specificato , il che implica sempre la possibilità di abbinare l'ordine dell'incontro. Non esiste una funzione di riproduzione casuale incorporata.
Holger

Risposte:


90
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));

La seconda riga uscirà sempre

Output:AAA
Output:BBB
Output:CCC

mentre il primo non è garantito in quanto l'ordine non viene mantenuto. forEachOrderedelaborerà gli elementi del flusso nell'ordine specificato dalla sua origine, indipendentemente dal fatto che il flusso sia sequenziale o parallelo.

Citando da forEachJavadoc:

Il comportamento di questa operazione è esplicitamente non deterministico. Per le pipeline di flusso parallelo, questa operazione non garantisce il rispetto dell'ordine di incontro del flusso, poiché così facendo si sacrificherebbe il vantaggio del parallelismo.

Quando il forEachOrderedJavadoc afferma (enfasi mia):

Esegue un'azione per ogni elemento di questo flusso, nell'ordine di incontro del flusso se il flusso ha un ordine di incontro definito.


6
Si hai ragione. È possibile solo per parallelStream?
gstackoverflow

6
Anche se al momento si applicasse solo ai flussi paralleli - e non sto dicendo che lo faccia - potrebbe comunque interrompersi in futuro se alcuni passaggi intermedi fossero ottimizzati per sfruttare i flussi non ordinati, ad esempio un ordinamento potrebbe utilizzare un algoritmo instabile se il flusso non è ordinato.
8472

1
Quindi non ha senso usare forEachOrderedcon parallel?
Bhushan

3
@BhushanPatil Sì, è corretto. stackoverflow.com/questions/47336825/…
Sagar

1
L'utilizzo di forEachOrdered elaborerà l'elemento per ordine, quindi l'utilizzo di flussi paralleli perderà i vantaggi del parallelismo. Per favore suggerisci.
Deepak

30

Anche se forEachpiù corto e sembra più carino, suggerirei di utilizzare forEachOrderedin ogni luogo in cui l'ordine è importante per specificarlo esplicitamente. Per i flussi sequenziali, forEachsembra rispettare l'ordine e persino il codice interno dell'API del flusso utilizza forEach (per il flusso che è noto per essere sequenziale) dove è semanticamente necessario da usare forEachOrdered! Tuttavia in seguito potresti decidere di modificare il tuo flusso in parallelo e il tuo codice verrà interrotto. Anche quando usiforEachOrdered il lettore del tuo codice compare il messaggio: "qui conta l'ordine". Così documenta meglio il tuo codice.

Nota anche che per i flussi paralleli forEachnon solo viene eseguito in ordine non determenistico, ma puoi anche farlo eseguire simultaneamente in thread diversi per elementi diversi (cosa che non è possibile con forEachOrdered).

Infine entrambi forEach/ forEachOrderedsono raramente utili. Nella maggior parte dei casi è effettivamente necessario produrre qualche risultato, non solo un effetto collaterale, quindi operazioni come reduceo collectdovrebbero essere più adatte. Esprimere un'operazione di riduzione per natura tramite forEachè generalmente considerato uno stile sbagliato.


7
"Infine, entrambi forEach / forEachOrdered sono raramente utili". Non potrei essere più d'accordo. Sembra che questi metodi siano troppo usati.
Tunaki

Grazie per la risposta. ma non è un esempio di vita reale. Ho appena imparato java 8
gstackoverflow il

Perché è semanticamente necessario utilizzare forEachOrderedin quel codice?
RealSkeptic,

1
@RealSkeptic, è il flusso specificato dall'utente (passato in flatMap). Può essere ordinato, quindi deve essere inserito nel flusso risultante nello stesso ordine.
Tagir Valeev

2
@RealSkeptic, sei il vero scettico! Stream.of("a", "b", "c").flatMap(s -> Stream.of("1", "2", "3").map(s::concat)).spliterator().hasCharacteristics(Spliterator.ORDERED)restituisce true, quindi è necessario determinare l'ordine per il flusso risultante. Se ritieni che la documentazione JDK debba dirlo esplicitamente, sentiti libero di inviare un bug.
Tagir Valeev

15

forEach()Il metodo esegue un'azione per ogni elemento di questo flusso. Per il flusso parallelo, questa operazione non garantisce il mantenimento dell'ordine del flusso.

forEachOrdered() Il metodo esegue un'azione per ogni elemento di questo flusso, garantendo che ogni elemento venga elaborato nell'ordine di incontro per i flussi che hanno un ordine di incontro definito.

prendi l'esempio di seguito:

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

Produzione:

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

sushil mittal

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

mihul issltat

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

sushil mittal
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.