peek () และ allMatch () ทำงานร่วมกันอย่างไรใน Java 8 Stream API


10

ฉันพบคำถามเกี่ยวกับ Java 8 Stream API ของวิธีการแอบดูด้านล่าง

Arrays.asList("Fred", "Jim", "Sheila")
      .stream()
      .peek(System.out::println)
      .allMatch(s -> s.startsWith("F"));

ผลลัพธ์คือ

Fred
Jim

ฉันสับสนว่าสตรีมนี้ทำงานอย่างไร ผลลัพธ์ที่คาดหวังของฉันควรจะเป็น

Fred
Jim
Sheila

peek () วิธีการคือการดำเนินการระดับกลางและจะประมวลผลแต่ละองค์ประกอบในสตรีม ใครสามารถอธิบายฉันนี้

คำตอบ:


10

มันเป็นการเพิ่มประสิทธิภาพของกระแสที่รู้จักกันในชื่อการลัดวงจร โดยพื้นฐานแล้วสิ่งที่เกิดขึ้นคือการallMatchป้องกันไม่ให้มีการดำเนินการระหว่างกลางที่ไม่จำเป็นบนสตรีมเนื่องจากไม่มีจุดในการดำเนินการเมื่อทราบผลลัพธ์สุดท้าย

ราวกับว่าสิ่งนี้เกิดขึ้น:

take"Fred"
peek("Fred")
evaluate("Fred".startsWith("F"))
decide whether the result of allMatch() is known for sure: Not yet

take"Jim"
peek("Jim")
evaluate("Jim".startsWith("F"))
decide whether the result of allMatch() is known for sure: Yes

เมื่อ"Jim".startsWith("F")มีการประเมินผลลัพธ์ของการallMatch(s -> s.startsWith("F"))เป็นที่รู้จักกันอย่างแน่นอน ไม่สำคัญว่าค่าใดที่มาในท่อหลังจาก"Jim"เรารู้ว่าค่าทั้งหมดที่ขึ้นต้นด้วย "F" นั้นเป็นเท็จ

สิ่งนี้ไม่ได้เฉพาะเจาะจงสำหรับpeek/ allMatchรวมกันมีการดำเนินการลัดวงจรระหว่างกลางและหลายสถานี สถานะjava.util.streamเอกสารของแพ็คเกจ :

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

ขยายสิ่งนี้ไปยังลำธารที่ จำกัด และการดำเนินการลัดวงจรกั้นการดำเนินการขั้นตอนไปป์ไลน์ที่ไม่จำเป็นเช่นในกรณีของตัวอย่างของคุณ


5
Arrays.asList("Fred", "Jim", "Sheila")
      .stream()
      .peek(System.out::println)
      .allMatch(s -> s.startsWith("F"));
  • ครั้งแรกที่ผ่านFredจะถูกพิมพ์ มันเข้าคู่กัน
  • ครั้งที่สองถึงJimจะถูกพิมพ์ ไม่ตรงกันดังนั้น allMatch จะสิ้นสุดลงเพราะ "ทั้งหมดไม่ตรงกัน"
  • ดังนั้นรายการสุดท้ายไม่ได้ถูกใช้จากสตรีม

3

เอกสารสำหรับpeekวิธีการพูด (เหมืองเน้น):

ผลตอบแทนที่ได้กระแสที่ประกอบด้วยองค์ประกอบของกระแสนี้นอกจากนี้ในการดำเนินการให้ในแต่ละองค์ประกอบเป็นองค์ประกอบที่มีการบริโภคจากกระแสที่เกิดขึ้น

ดังนั้นในกรณีpeekนี้ไม่เห็น"Sheila"เนื่องจากไม่มีการใช้ค่านั้นจากสตรีม ทันทีที่"Jim"ถูกบริโภคผลลัพธ์ของการ.allMatch(s -> s.startsWith("F"))เป็นที่ทราบกันดีอยู่แล้วfalseจึงไม่จำเป็นต้องใช้องค์ประกอบเพิ่มเติมใด ๆ จากกระแสข้อมูล


1

ตามเอกสารของ Java AllMatch ():

ส่งคืนว่าองค์ประกอบทั้งหมดของสตรีมนี้ตรงกับภาคแสดงหรือไม่ อาจไม่ประเมินเพรดิเคตสำหรับองค์ประกอบทั้งหมดหากไม่จำเป็นสำหรับการพิจารณาผลลัพธ์ หากสตรีมนั้นว่างแล้ว {@code true} จะถูกส่งคืนและเพรดิเคตจะไม่ถูกประเมิน

@apiNote

วิธีการนี้ประเมินผลเชิงปริมาณสากลของเพรดิเคตเหนือองค์ประกอบของสตรีม (สำหรับ x ทั้งหมด (x) หากสตรีมว่างเปล่าการบอกปริมาณจะได้รับการตอบสนองที่ว่างและ {@ รหัส true} เสมอ (โดยไม่คำนึงถึง P (x))

เพรดิเคตเพื่อใช้กับองค์ประกอบของสตรีมนี้ @return {@code true} หากองค์ประกอบทั้งหมดของสตรีมตรงกับเพรดิเคตที่ระบุหรือสตรีมนั้นว่างเปล่ามิฉะนั้น {@code false}

ในกรณีของคุณ:

1-

p(x) : s -> s.startsWith("F")

X : "Fred"

result : X P(X) = true

2-

p(x) : s -> s.startsWith("F")

X : "Jim"

result : X P(X) = false

จะไม่มีการประเมินผลเพิ่มเติมเนื่องจาก XP (X) = false

boolean result = Arrays.asList("Fred", "Finda", "Fish")
            .stream()
            .peek(System.out::println)
            .allMatch(s -> s.startsWith("F"));
    System.out.println("Result "+result);

ผลลัพธ์คือ:

Fred
Finda
Fish
Result true

สตรีมที่นี่ประมวลผลอย่างสมบูรณ์เนื่องจาก xP (x) = true จากแต่ละองค์ประกอบ

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