forEach vs forEachOrdered Java 8 Stream


87

Bu yöntemlerin yürütme sırasından farklı olduğunu anlıyorum, ancak tüm testlerimde farklı emir yürütmeyi başaramıyorum.

Misal:

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

Çıktı:

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

Lütfen 2 yöntemin farklı çıktılar üreteceği örnekler veriniz.


Paralel akışlarla deneyebilirsiniz.
Pshemo

@Pshemo tek olası seçenek mi?
gstackoverflow

5
Belirtilmemiş sipariş, "farklı sipariş olması garantili" anlamına gelmez. Sadece belirtilmemiş anlamına gelir , bu da her zaman karşılaşma sırasına uyma olasılığını ifade eder. Yerleşik karıştırma işlevi yoktur.
Holger

Yanıtlar:


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

İkinci satır her zaman çıkacak

Output:AAA
Output:BBB
Output:CCC

oysa sipariş tutulmadığı için birincisi garantili değildir. forEachOrderedAkışın sıralı veya paralel olup olmadığına bakılmaksızın, akışın öğelerini kaynağı tarafından belirtilen sırayla işler.

Javadoc'tan alıntı forEach:

Bu işlemin davranışı açıkça belirleyici değildir. Paralel akışlı boru hatları için, bu işlem, akışın karşılaşma sırasına uymayı garanti etmez, çünkü böyle yapmak, paralellik avantajından ödün verir.

forEachOrderedJavadoc ifade ettiğinde (vurgu benim):

Akışın tanımlanmış bir karşılaşma sırasına sahip olması durumunda, akışın karşılaşma sırasına göre bu akışın her bir öğesi için bir eylem gerçekleştirir .


6
Evet haklısın. Yalnızca parallelStreams için mümkün mü?
gstackoverflow

6
Şu anda yalnızca paralel akışlar için geçerli olsa bile - ve öyle olduğunu söylemiyorum - sırasız akışlardan yararlanmak için bazı ara adımlar optimize edilirse, gelecekte yine de bozulabilir, örneğin, eğer bir sıralama kararsız bir algoritma kullanabilir akış sırasız.
the8472

1
Kullanmak için hiçbir mantıklı Yani forEachOrderedbirlikte parallel?
Bhushan

3
@BhushanPatil Evet, bu doğru. stackoverflow.com/questions/47336825/…
Sagar

1
ForEachOrdered kullanmak, öğeyi sırayla işleyecek, ardından paralel akışları kullanmak paralelliğin faydalarını kaybedecektir. Lütfen önerin.
Deepak

30

Daha forEachkısa ve daha güzel görünse de, bunu forEachOrderedaçıkça belirtmek için siparişin önemli olduğu her yerde kullanmanızı öneririm . Sıralı akışlar için , semantik olarak kullanılmasının gerekli olduğu forEachAPI dahili kodlarının (sıralı olduğu bilinen akış için) kullanım sırasına ve hatta akışa saygı duyduğu görülmektedir ! Yine de daha sonra akışınızı paralel olarak değiştirmeye karar verebilirsiniz ve kodunuz kırılır. Ayrıca kodunuzun okuyucusunu kullandığınızda , "sipariş burada önemlidir" mesajını görür. Böylece kodunuzu daha iyi belgeler.forEachforEachOrderedforEachOrdered

Paralel akışlar için forEachyalnızca deterministik olmayan sırada yürütülmekle kalmayıp, aynı zamanda farklı öğeler için farklı evrelerde eşzamanlı olarak da çalıştırabileceğinizi unutmayın (bu mümkün değildir forEachOrdered).

Son olarak her ikisi forEach/ forEachOrderednadiren faydalıdır. Çoğu durumda, sadece yan etkiye değil, aslında bir sonuç üretmeniz gerekir; bu nedenle, benzer reduceveya collectdaha uygun işlemler yapılmalıdır. Doğası gereği azaltma işlemini yoluyla ifade forEachetmek genellikle kötü bir tarz olarak kabul edilir.


7
"Son olarak hem forEach / forEachOrdered nadiren faydalıdır". Daha fazla katılamazdım. Görünüşe göre bu yöntemler fazla kullanılıyor.
Tunaki

Cevap için teşekkürler. ama gerçek hayattan bir örnek değil. Sadece java 8 öğreniyorum
gstackoverflow

forEachOrderedBu kodda kullanmak neden anlamsal olarak gerekli ?
RealSkeptic

1
@RealSkeptic, kullanıcı tarafından belirlenen akış (içine aktarılır flatMap). Sipariş edilebilir, bu nedenle ortaya çıkan akışa aynı sırayla yerleştirilmelidir.
Tagir Valeev

2
@RealSkeptic, gerçek şüphecisin! Stream.of("a", "b", "c").flatMap(s -> Stream.of("1", "2", "3").map(s::concat)).spliterator().hasCharacteristics(Spliterator.ORDERED)true değerini döndürür, bu nedenle ortaya çıkan akışın sırasının belirlenmesi gerekir. JDK belgelerinin bunu açıkça belirtmesi gerektiğini düşünüyorsanız, bir hata göndermekten çekinmeyin.
Tagir Valeev

15

forEach()yöntem, bu akışın her bir öğesi için bir eylem gerçekleştirir. Paralel akış için, bu işlem akışın sırasını korumayı garanti etmez.

forEachOrdered() yöntem, bu akışın her bir öğesi için bir eylem gerçekleştirerek, her öğenin, tanımlanmış bir karşılaşma sırasına sahip akışlar için karşılaşma sırasına göre işlenmesini garanti eder.

aşağıdaki örneği ele alalım:

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

Çıktı:

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

sushil mittal

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

mihul issltat

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

sushil mittal
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.