forEach เทียบกับ forEachOrder ใน Java 8 Stream


87

ฉันเข้าใจว่าวิธีการเหล่านี้ลำดับการดำเนินการแตกต่างกัน แต่ในการทดสอบทั้งหมดของฉันฉันไม่สามารถดำเนินการตามคำสั่งที่แตกต่างกันได้

ตัวอย่าง:

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

เอาท์พุต:

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

โปรดยกตัวอย่างเมื่อ 2 วิธีจะให้ผลลัพธ์ที่แตกต่างกัน


ลองใช้สตรีมคู่ขนาน
Pshemo

@Pshemo เป็นทางเลือกเดียวที่เป็นไปได้?
gstackoverflow

5
คำสั่งซื้อที่ไม่ระบุไม่ได้หมายความว่า "รับประกันว่าจะเป็นคำสั่งซื้อที่แตกต่างกัน" มันหมายถึงไม่ระบุซึ่งแสดงถึงความเป็นไปได้ที่จะตรงกับลำดับการเผชิญหน้าเสมอ ไม่มีฟังก์ชันสับเปลี่ยนในตัว
Holger

คำตอบ:


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

บรรทัดที่สองจะแสดงผลเสมอ

Output:AAA
Output:BBB
Output:CCC

ในขณะที่รายการแรกไม่ได้รับการรับประกันเนื่องจากไม่ได้เก็บคำสั่งซื้อไว้ forEachOrderedจะประมวลผลองค์ประกอบของสตรีมตามลำดับที่ระบุโดยแหล่งที่มาไม่ว่าสตรีมจะเรียงตามลำดับหรือขนานกันก็ตาม

อ้างจากforEachJavadoc:

พฤติกรรมของการดำเนินการนี้ไม่แน่นอนอย่างชัดเจน สำหรับท่อส่งกระแสคู่ขนานการดำเนินการนี้ไม่รับประกันว่าจะเคารพลำดับการเผชิญหน้าของสตรีมเนื่องจากการทำเช่นนั้นจะเสียสละประโยชน์ของความขนาน

เมื่อforEachOrderedรัฐ Javadoc (เน้นของฉัน):

ดำเนินการสำหรับแต่ละองค์ประกอบของสตรีมนี้ตามลำดับการเผชิญหน้าของสตรีมหากสตรีมมีลำดับการเผชิญหน้าที่กำหนดไว้


6
ใช่คุณถูก. เป็นไปได้เฉพาะสำหรับ parallelStreams หรือไม่?
gstackoverflow

6
แม้ว่าตอนนี้จะใช้กับสตรีมคู่ขนานเท่านั้น - และฉันไม่ได้บอกว่ามันเป็นเช่นนั้น - มันยังอาจพังในอนาคตหากขั้นตอนกลางบางขั้นตอนได้รับการปรับให้เหมาะสมเพื่อใช้ประโยชน์จากสตรีมที่ไม่ได้เรียงลำดับเช่นการเรียงลำดับอาจใช้อัลกอริทึมที่ไม่เสถียรหาก สตรีมไม่เรียงลำดับ
the8472

1
จึงไม่สมเหตุสมผลที่จะใช้forEachOrderedกับparallel?
Bhushan

3
@BhushanPatil ใช่ถูกต้อง stackoverflow.com/questions/47336825/…
Sagar

1
การใช้ forEachOrder จะประมวลผลองค์ประกอบตามคำสั่งจากนั้นการใช้สตรีมแบบขนานจะทำให้ประโยชน์ของการขนานขาดหายไป ช่วยแนะนำหน่อยครับ.
Deepak

30

แม้ว่าจะforEachสั้นกว่าและดูสวยกว่า แต่ฉันขอแนะนำให้ใช้forEachOrderedในทุกสถานที่ที่มีความสำคัญในการระบุสิ่งนี้อย่างชัดเจน สำหรับสตรีมแบบต่อเนื่องforEachดูเหมือนว่าจะเคารพคำสั่งและแม้กระทั่งการสตรีมรหัสภายในของ API จะใช้ forEach (สำหรับสตรีมซึ่งเป็นที่ทราบกันดีว่าเป็นลำดับ) ซึ่งจำเป็นต้องใช้ทางความหมายforEachOrdered! อย่างไรก็ตามคุณอาจตัดสินใจเปลี่ยนสตรีมเป็นแบบขนานในภายหลังและโค้ดของคุณจะเสีย นอกจากนี้เมื่อคุณใช้forEachOrderedโปรแกรมอ่านรหัสของคุณจะเห็นข้อความ "คำสั่งซื้อมีความสำคัญที่นี่" ดังนั้นเอกสารของคุณจึงดีกว่า

โปรดทราบด้วยว่าสำหรับสตรีมแบบขนานforEachไม่เพียง แต่ดำเนินการในลำดับที่ไม่ได้กำหนด แต่คุณยังสามารถดำเนินการพร้อมกันในเธรดที่แตกต่างกันสำหรับองค์ประกอบที่แตกต่างกัน (ซึ่งไม่สามารถทำได้ด้วยforEachOrdered)

ในที่สุดทั้งสองforEach/ forEachOrderedแทบไม่มีประโยชน์ ในกรณีส่วนใหญ่คุณจำเป็นต้องสร้างผลลัพธ์บางอย่างไม่ใช่แค่ผลข้างเคียงดังนั้นการดำเนินการที่เหมือนreduceหรือcollectควรจะเหมาะสมกว่า โดยforEachปกติแล้วการแสดงการดำเนินการลดโดยธรรมชาติถือเป็นลักษณะที่ไม่ดี


7
"ในที่สุดทั้ง forEach / forEachOr ผงจะไม่ค่อยมีประโยชน์" ฉันไม่สามารถยอมรับมากขึ้น. ดูเหมือนว่าวิธีการเหล่านี้จะใช้มากเกินไป
Tunaki

ขอบคุณสำหรับคำตอบ. แต่มันไม่ใช่ตัวอย่างชีวิตจริง ฉันเพิ่งเรียนรู้ java 8
gstackoverflow

เหตุใดจึงจำเป็นต้องใช้forEachOrderedในรหัสนั้นในเชิงความหมาย
RealSkeptic

1
@RealSkeptic เป็นสตรีมที่ผู้ใช้ระบุ (ส่งผ่านไปยังflatMap) สามารถสั่งซื้อได้ดังนั้นจึงต้องวางลงในสตรีมผลลัพธ์ในลำดับเดียวกัน
Tagir Valeev

2
@RealSkeptic คุณเป็นคนขี้ระแวงจริง! Stream.of("a", "b", "c").flatMap(s -> Stream.of("1", "2", "3").map(s::concat)).spliterator().hasCharacteristics(Spliterator.ORDERED)ส่งคืนจริงดังนั้นจึงต้องกำหนดลำดับสำหรับสตรีมผลลัพธ์ หากคุณรู้สึกว่าเอกสารของ JDK ควรพูดอย่างชัดเจนเกี่ยวกับเรื่องนี้โปรดอย่าลังเลที่จะส่งข้อบกพร่อง
Tagir Valeev

15

forEach()วิธีการดำเนินการสำหรับแต่ละองค์ประกอบของสตรีมนี้ สำหรับสตรีมแบบขนานการดำเนินการนี้ไม่รับประกันว่าจะรักษาลำดับของสตรีม

forEachOrdered() วิธีดำเนินการสำหรับแต่ละองค์ประกอบของสตรีมนี้โดยรับประกันว่าแต่ละองค์ประกอบได้รับการประมวลผลตามลำดับการเผชิญหน้าสำหรับสตรีมที่มีลำดับการเผชิญหน้าที่กำหนดไว้

ดูตัวอย่างด้านล่าง:

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

เอาท์พุต:

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

sushil mittal

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

mihul issltat

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

sushil mittal
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.