ค้นหาองค์ประกอบ
ตอนนี้เราคุ้นเคยกับวิธีการเปลี่ยนคอลเลกชันที่ออกแบบมาอย่างหรูหราแล้ว แต่การค้นหาองค์ประกอบต่างๆ ก็ไม่มีประโยชน์ แต่วิธีการกรองก็เกิดมาเพื่อสิ่งนี้
ตอนนี้เราต้องการลบชื่อที่ขึ้นต้นด้วย N ออกจากรายชื่อ แน่นอนว่าอาจไม่มีเลย และผลลัพธ์อาจเป็นเซตว่าง เรามาปรับใช้กันก่อนโดยใช้วิธีเก่า
คัดลอกรหัสรหัสดังต่อไปนี้:
รายการสุดท้าย<String> startWithN = new ArrayList<String>();
สำหรับ (ชื่อสตริง : เพื่อน) {
ถ้า(name.startsWith("N")) {
startWithN.add(ชื่อ);
-
-
การเขียนโค้ดจำนวนมากสำหรับเหตุการณ์ง่ายๆ เช่นนี้ค่อนข้างละเอียด ขั้นแรกเราสร้างตัวแปรแล้วเริ่มต้นให้เป็นคอลเลกชันว่าง จากนั้นวนซ้ำคอลเลกชันดั้งเดิมและค้นหาชื่อที่ขึ้นต้นด้วยตัวอักษรที่ระบุ หากพบจะแทรกเข้าไปในคอลเลกชัน
ลองใช้วิธีกรองเพื่อสร้างโค้ดด้านบนใหม่เพื่อดูว่ามันมีประสิทธิภาพเพียงใด
คัดลอกรหัสรหัสดังต่อไปนี้:
รายการสุดท้าย <String> startWithN =
เพื่อน.สตรีม()
.filter(ชื่อ -> name.startsWith("N"))
.collect(Collectors.toList());
วิธีการกรองได้รับนิพจน์แลมบ์ดาที่ส่งกลับค่าบูลีน หากนิพจน์ประเมินเป็นจริง องค์ประกอบนั้นในบริบทการดำเนินการจะถูกเพิ่มเข้ากับชุดผลลัพธ์ หากไม่ใช่ องค์ประกอบนั้นจะถูกข้ามไป ในที่สุดสิ่งที่ได้กลับมาก็คือ Steam ซึ่งบรรจุเฉพาะองค์ประกอบที่นิพจน์คืนค่าเป็น "จริง" ในที่สุดเราก็ใช้วิธีการรวบรวมเพื่อแปลงคอลเลกชันเป็นรายการ - เราจะพูดถึงวิธีการนี้ในเชิงลึกมากขึ้นในการใช้วิธีการรวบรวมและคลาส Collecters ในหน้า 52
มาพิมพ์องค์ประกอบในชุดผลลัพธ์นี้:
คัดลอกรหัสรหัสดังต่อไปนี้:
System.out.println(String.format("พบ %d ชื่อ", startWithN.size()));
จากผลลัพธ์จะเห็นได้ชัดเจนว่าวิธีนี้พบองค์ประกอบที่ตรงกันทั้งหมดในคอลเลกชัน
คัดลอกรหัสรหัสดังต่อไปนี้:
เจอ 2 ชื่อ.
วิธีการกรอง เช่นเดียวกับวิธีการ map จะส่งกลับตัววนซ้ำเช่นกัน แต่ก็แค่นั้นแหละ คอลเลกชันที่ส่งคืนโดยแผนที่มีขนาดเดียวกับคอลเลกชันอินพุต แต่เป็นการยากที่จะบอกว่าตัวกรองใดส่งคืน ช่วงขนาดของชุดที่ส่งคืน ตั้งแต่ 0 ถึงจำนวนองค์ประกอบในชุดอินพุต ไม่เหมือนกับแผนที่ ตัวกรองจะส่งกลับชุดย่อยของชุดอินพุต
จนถึงตอนนี้ เราพอใจมากกับความเรียบง่ายของโค้ดที่เกิดจากนิพจน์ lambda แต่หากเราไม่ระวัง ปัญหาของความซ้ำซ้อนของโค้ดจะเริ่มเพิ่มขึ้นอย่างช้าๆ มาหารือเกี่ยวกับปัญหานี้ด้านล่าง
การใช้นิพจน์แลมบ์ดาซ้ำ
นิพจน์ Lambda ดูกระชับมาก แต่ในความเป็นจริงแล้ว การสร้างโค้ดซ้ำซ้อนนั้นเป็นเรื่องง่ายหากคุณไม่ระวัง ความซ้ำซ้อนจะทำให้โค้ดมีคุณภาพต่ำและมีความยุ่งยากในการบำรุงรักษา หากเราต้องการเปลี่ยนแปลง เราต้องเปลี่ยนโค้ดที่เกี่ยวข้องหลายรายการพร้อมกัน
การหลีกเลี่ยงความซ้ำซ้อนยังสามารถช่วยเราปรับปรุงประสิทธิภาพได้อีกด้วย โค้ดที่เกี่ยวข้องรวมอยู่ในที่เดียว เพื่อให้เราสามารถวิเคราะห์ประสิทธิภาพของโค้ดแล้วปรับโค้ดให้เหมาะสมที่นี่ ซึ่งสามารถปรับปรุงประสิทธิภาพของโค้ดได้อย่างง่ายดาย
ตอนนี้เรามาดูกันว่าเหตุใดการใช้นิพจน์แลมบ์ดาจึงทำให้เกิดความซ้ำซ้อนของโค้ดได้อย่างง่ายดาย และพิจารณาวิธีหลีกเลี่ยง
คัดลอกรหัสรหัสดังต่อไปนี้:
รายการสุดท้าย <String> เพื่อน =
Arrays.asList("ไบรอัน", "เนท", "นีล", "ราจู", "ซาร่า", "สกอตต์");
รายการสุดท้าย <String> บรรณาธิการ =
Arrays.asList("ไบรอัน", "แจ็กกี้", "จอห์น", "ไมค์");
รายการสุดท้าย <String> สหาย =
Arrays.asList("เคท", "เคน", "นิค", "พอลล่า", "แซค");
เราต้องการกรองชื่อที่ขึ้นต้นด้วยตัวอักษรบางตัวออก
เราต้องการกรองชื่อที่ขึ้นต้นด้วยตัวอักษรบางตัว เรามาลองใช้วิธีกรองกันก่อน
คัดลอกรหัสรหัสดังต่อไปนี้:
countFriendsStartN ยาวครั้งสุดท้าย =
เพื่อน.สตรีม()
.filter(ชื่อ -> name.startsWith("N")).count();
การนับยาวครั้งสุดท้ายEditorsStartN =
บรรณาธิการ.สตรีม()
.filter(ชื่อ -> name.startsWith("N")).count();
countComradesStartN ยาวสุดท้าย =
สหาย.สตรีม()
.filter(ชื่อ -> name.startsWith("N")).count();
นิพจน์ Lambda ทำให้โค้ดดูกระชับ แต่กลับนำความซ้ำซ้อนมาสู่โค้ดโดยไม่รู้ตัว ในตัวอย่างข้างต้น หากเราต้องการเปลี่ยนนิพจน์ lambda เราต้องเปลี่ยนมากกว่าหนึ่งตำแหน่ง ซึ่งเป็นไปไม่ได้ โชคดีที่เราสามารถกำหนดนิพจน์แลมบ์ดาให้กับตัวแปรและนำมาใช้ซ้ำได้เหมือนกับออบเจ็กต์
วิธีการกรอง ซึ่งเป็นตัวรับของนิพจน์แลมบ์ดา ได้รับการอ้างอิงถึงอินเทอร์เฟซการทำงาน java.util.function.Predicate ที่นี่ คอมไพเลอร์ Java มีประโยชน์อีกครั้ง โดยสร้างการใช้งานวิธีทดสอบของภาคแสดงโดยใช้นิพจน์แลมบ์ดาที่ระบุ ตอนนี้เราสามารถขอให้คอมไพเลอร์ Java สร้างเมธอดนี้ได้ชัดเจนยิ่งขึ้น แทนที่จะสร้างเมธอดนี้โดยที่พารามิเตอร์ถูกกำหนดไว้ ในตัวอย่างข้างต้น เราสามารถจัดเก็บนิพจน์แลมบ์ดาไว้ในการอ้างอิงประเภทเพรดิเคตได้อย่างชัดเจน จากนั้นส่งต่อการอ้างอิงนี้ไปยังวิธีการกรอง ซึ่งจะช่วยหลีกเลี่ยงความซ้ำซ้อนของโค้ดได้อย่างง่ายดาย
มาปรับโครงสร้างโค้ดก่อนหน้าใหม่เพื่อให้เป็นไปตามหลักการ DRY (Don't Repeat Yoursef - DRY - หลักการ โปรดดูหนังสือ The Pragmatic Programmer: From Journeyman to Master [HT00])
คัดลอกรหัสรหัสดังต่อไปนี้:
ภาคแสดงสุดท้าย <String> startWithN = name -> name.startsWith("N");
countFriendsStartN ยาวครั้งสุดท้าย =
เพื่อน.สตรีม()
.filter (เริ่มต้นด้วย N)
.นับ();
การนับยาวครั้งสุดท้ายEditorsStartN =
บรรณาธิการ.สตรีม()
.filter (เริ่มต้นด้วย N)
.นับ();
countComradesStartN ยาวสุดท้าย =
สหาย.สตรีม()
.filter (เริ่มต้นด้วย N)
.นับ();
ตอนนี้แทนที่จะเขียนนิพจน์แลมบ์ดาอีกครั้ง เราเขียนมันเพียงครั้งเดียวและเก็บไว้ในการอ้างอิงประเภทเพรดิเคตที่เรียกว่า startWithN ในการเรียกตัวกรองสามครั้งต่อไปนี้ คอมไพเลอร์ Java เห็นนิพจน์แลมบ์ดาที่ปลอมตัวเป็นเพรดิเคต จึงยิ้มและยอมรับมันอย่างเงียบๆ
ตัวแปรที่เพิ่งเปิดตัวนี้ช่วยลดความซ้ำซ้อนของโค้ดสำหรับเรา แต่น่าเสียดายอย่างที่เราจะได้เห็นในภายหลัง ศัตรูจะกลับมาแก้แค้นในไม่ช้า มาดูกันว่าจะมีอาวุธอะไรที่ทรงพลังกว่าที่จะทำลายพวกมันให้เราได้