Java - กรองสตรีมด้วย Lambda Expressions PlatoBlockchain Data Intelligence ค้นหาแนวตั้ง AI.

Java – กรองสตรีมด้วย Lambda Expressions

Java Streams ได้รับการแนะนำมาตลอดทางใน Java 8 ในปี 2014 ด้วยความพยายามที่จะแนะนำ verbose Java ให้กับกระบวนทัศน์การเขียนโปรแกรมเชิงฟังก์ชัน Java Streams แสดงการทำงานที่ยืดหยุ่นและทรงพลังมากมายเพื่อดำเนินการประมวลผลคอลเลกชันในหนึ่งซับ

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

ในคำแนะนำสั้นๆ นี้ เราจะมาดูกันว่าคุณจะกรองสตรีม Java 8 ด้วย Lambda Expressions ได้อย่างไร

การกรองสตรีมใน Java

โดยทั่วไป ใดๆ Stream สามารถคัดกรองได้ทาง filter() วิธีการและภาคแสดงที่กำหนด:

Stream filter(Predicate<? super T> predicate)

แต่ละอิลิเมนต์ในสตรีมจะรันกับเพรดิเคต และจะถูกเพิ่มในสตรีมเอาท์พุตหากเพรดิเคตส่งกลับ true. คุณสามารถจัดหา Predicate ตัวอย่าง:

Predicate contains = s -> s.contains("_deprecated");
List results = stream.filter(contains).collect(Collectors.toList());

หรือทำให้ง่ายขึ้นด้วยการจัดเตรียม Lambda Expression:

List results = stream.filter(s -> s.contains("_deprecated"))
                             .collect(Collectors.toList());

หรือแม้กระทั่งยุบ Lambda Expression เป็น a การอ้างอิงวิธีการ:


List results = stream.filter(String::isEmpty)
                             .collect(Collectors.toList());

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

โปรดจำไว้ว่า สตรีมไม่ใช่ของสะสม - พวกเขากำลังสตรีม ของคอลเลกชันและคุณจะต้องรวบรวมกลับเข้าไปในคอลเล็กชันใดๆ เช่น List, Mapฯลฯ เพื่อให้มีความคงทนถาวร นอกจากนี้ การดำเนินการทั้งหมดที่ทำกับองค์ประกอบสตรีมก็เช่นกัน สื่อกลาง or สถานีปลายทาง:

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

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

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

ในตัวอย่างต่อไปนี้ เราจะดำเนินการกับรายการหนังสือนี้:

Book book1 = new Book("001", "Our Mathematical Universe", "Max Tegmark", 432, 2014);
Book book2 = new Book("002", "Life 3.0", "Max Tegmark", 280, 2017);
Book book3 = new Book("003", "Sapiens", "Yuval Noah Harari", 443, 2011);
        
List books = Arrays.asList(book1, book2, book3);

การรวบรวมตัวกรองด้วย Stream.filter()

มากรองหนังสือชุดนี้กัน เพรดิเคตอะไรก็ได้ เช่น กรองตามหนังสือที่มีมากกว่า 400 หน้า:

List results = books.stream()
                          .filter(b -> b.getPageNumber() > 400)
                          .collect(Collectors.toList());

ส่งผลให้รายการประกอบด้วย:

[
Book{id='001', name='Our Mathematical Universe', author='Max Tegmark', pageNumber=432, publishedYear=2014}, 
Book{id='003', name='Sapiens', author='Yuval Noah Harari', pageNumber=443, publishedYear=2011}
]

เมื่อทำการกรอง วิธีที่มีประโยชน์มากในการโยงคือ map()ซึ่งช่วยให้คุณแมปวัตถุกับค่าอื่นได้ ตัวอย่างเช่น เราสามารถแมปหนังสือแต่ละเล่มกับชื่อของมัน และส่งกลับเฉพาะ the ชื่อ ของหนังสือที่เหมาะกับภาคแสดงจาก filter() โทร:

List results = books.stream()
                            .filter(b -> b.getPageNumber() > 400)
                            .map(Book::getName)
                            .collect(Collectors.toList());

ส่งผลให้รายการสตริง:

[Our Mathematical Universe, Sapiens]

การรวบรวมตัวกรองในหลายภาคแสดงด้วย Stream.filter()

โดยทั่วไป เราต้องการกรองคอลเลกชันตามเกณฑ์มากกว่าหนึ่งเกณฑ์ ซึ่งสามารถทำได้โดยการผูกมัดหลายๆ filter() โทร or โดยใช้เพรดิเคตลัดวงจรซึ่งจะตรวจสอบสองเงื่อนไขในหนึ่งเดียว filter() โทร.

 List results = books.stream()
                    .filter(b -> b.getPageNumber() > 400 && b.getName().length() > 10)
                    .collect(Collectors.toList());
                    


 List results2 = books.stream()
                    .filter(b -> b.getPageNumber() > 400)
                    .filter(b -> b.getName().length() > 10)
                    .collect(Collectors.toList());

ดูคู่มือเชิงปฏิบัติสำหรับการเรียนรู้ Git ที่มีแนวทางปฏิบัติที่ดีที่สุด มาตรฐานที่ยอมรับในอุตสาหกรรม และเอกสารสรุปรวม หยุดคำสั่ง Googling Git และจริงๆ แล้ว เรียน มัน!

เมื่อใช้หลายเกณฑ์ การเรียกใช้แลมบ์ดาอาจใช้เวลานานพอสมควร ณ จุดนี้ การแยกเป็นเพรดิเคตแบบสแตนด์อโลนอาจให้ความชัดเจนมากขึ้น แม้ว่าวิธีการใดจะเร็วกว่า

ตัวกรองเดี่ยวที่มีเงื่อนไขซับซ้อนหรือตัวกรองหลายตัว

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

ทางเลือกที่ดีที่สุดคือลองทั้งสองอย่าง สังเกตประสิทธิภาพของ อุปกรณ์เป้าหมายและปรับกลยุทธ์ของคุณให้เหมาะสม

ผู้ใช้ GitHub โฟล์คสวาเกน ทำเกณฑ์มาตรฐานการกรองในการดำเนินการปริมาณงาน และโฮสต์ผลลัพธ์บน “javafilters-มาตรฐาน” ที่เก็บ ผลลัพธ์สรุปไว้ในตารางข้อมูล:

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

ประทับเวลา:

เพิ่มเติมจาก สแต็ค