forEach vs forEachOrdered di Java 8 Stream

87

Saya memahami bahwa metode ini membedakan urutan eksekusi tetapi dalam semua pengujian saya, saya tidak dapat mencapai eksekusi pesanan yang berbeda.

Contoh:

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

Keluaran:

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

Berikan contoh ketika 2 metode akan menghasilkan keluaran yang berbeda.

gstackoverflow
sumber
Coba mungkin dengan aliran paralel.
Pshemo
@Pshemo apakah itu hanya pilihan yang mungkin?
gstackoverflow
5
Pesanan yang tidak ditentukan tidak menyiratkan "dijamin untuk menjadi pesanan berbeda". Itu hanya berarti tidak ditentukan , yang selalu menyiratkan kemungkinan untuk mencocokkan urutan pertemuan. Tidak ada fungsi shuffle built-in.
Holger

Jawaban:

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

Baris kedua akan selalu keluar

Output:AAA
Output:BBB
Output:CCC

sedangkan yang pertama tidak dijamin karena pesanan tidak disimpan. forEachOrderedakan memproses elemen aliran dalam urutan yang ditentukan oleh sumbernya, terlepas dari apakah aliran tersebut berurutan atau paralel.

Mengutip dari forEachJavadoc:

Perilaku operasi ini secara eksplisit tidak deterministik. Untuk pipa aliran paralel, operasi ini tidak menjamin untuk menghormati urutan pertemuan aliran, karena hal itu akan mengorbankan manfaat paralelisme.

Ketika forEachOrderedJavadoc menyatakan (penekanan saya):

Melakukan tindakan untuk setiap elemen aliran ini, dalam urutan pertemuan aliran jika aliran memiliki urutan pertemuan yang ditentukan.

Tunaki
sumber
6
Ya kamu benar. Apakah hanya mungkin untuk parallelStreams?
gstackoverflow
6
Bahkan jika itu hanya akan berlaku untuk aliran paralel sekarang - dan saya tidak mengatakannya demikian - itu masih mungkin rusak di masa depan jika beberapa langkah perantara dioptimalkan untuk memanfaatkan aliran tidak berurutan, misalnya semacam dapat menggunakan algoritma yang tidak stabil jika alirannya tidak berurutan.
the8472
1
Jadi tidak masuk akal untuk digunakan forEachOrdereddengan parallel?
Bhushan
3
@BhushanPatil Ya, itu benar. stackoverflow.com/questions/47336825/…
Sagar
1
Menggunakan forEachOrdered akan memproses elemen demi pesanan kemudian menggunakan aliran paralel akan kehilangan manfaat dari paralelisme. Mohon saran.
Deepak
30

Meskipun forEachlebih pendek dan terlihat lebih cantik, saya sarankan untuk menggunakan forEachOrdereddi setiap tempat di mana urutan penting untuk menentukan ini secara eksplisit. Untuk aliran sekuensial, forEachtampaknya menghormati urutan dan bahkan menggunakan kode internal API streaming forEach(untuk aliran yang dikenal berurutan) di mana itu secara semantik perlu digunakan forEachOrdered! Namun demikian, Anda nantinya dapat memutuskan untuk mengubah aliran Anda menjadi paralel dan kode Anda akan rusak. Juga ketika Anda menggunakan forEachOrderedpembaca kode Anda melihat pesan: "urutan penting di sini". Dengan demikian, ini mendokumentasikan kode Anda dengan lebih baik.

Perhatikan juga bahwa untuk aliran paralel, forEachtidak hanya dijalankan dalam urutan non-determenistik, tetapi Anda juga dapat menjalankannya secara bersamaan di utas yang berbeda untuk elemen yang berbeda (yang tidak dimungkinkan dengan forEachOrdered).

Akhirnya keduanya forEach/ forEachOrderedjarang berguna. Dalam kebanyakan kasus, Anda benar-benar perlu menghasilkan beberapa hasil, bukan hanya efek samping, sehingga operasi seperti reduceatau collectseharusnya lebih sesuai. Mengekspresikan operasi pengurangan sifat melalui forEachbiasanya dianggap sebagai gaya yang buruk.

Tagir Valeev
sumber
7
"Terakhir, forEach / forEachOrdered jarang berguna". Saya sangat setuju. Tampaknya metode ini digunakan secara berlebihan.
Tunaki
Terima kasih atas jawabannya. tapi ini bukan contoh kehidupan nyata. Saya baru belajar java 8
gstackoverflow
Mengapa secara semantik perlu digunakan forEachOrdereddalam kode itu?
RealSkeptic
1
@RealSkeptic, ini adalah aliran yang ditentukan pengguna (diteruskan ke flatMap). Itu dapat dipesan, sehingga harus ditempatkan ke aliran yang dihasilkan dalam urutan yang sama.
Tagir Valeev
2
@RealSkeptic, Anda benar-benar skeptis! Stream.of("a", "b", "c").flatMap(s -> Stream.of("1", "2", "3").map(s::concat)).spliterator().hasCharacteristics(Spliterator.ORDERED)mengembalikan nilai true, sehingga urutan aliran yang dihasilkan harus ditentukan. Jika Anda merasa bahwa dokumentasi JDK harus secara eksplisit menyatakan hal ini, silakan kirimkan bug.
Tagir Valeev
15

forEach()metode melakukan tindakan untuk setiap elemen aliran ini. Untuk aliran paralel, operasi ini tidak menjamin untuk menjaga ketertiban aliran.

forEachOrdered() metode melakukan tindakan untuk setiap elemen aliran ini, menjamin bahwa setiap elemen diproses dalam urutan pertemuan untuk aliran yang memiliki urutan pertemuan yang ditentukan.

ambil contoh di bawah ini:

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

Keluaran:

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

sushil mittal

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

mihul issltat

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

sushil mittal
Sushil Mittal
sumber