ด้วย Java เวอร์ชันใหม่แต่ละเวอร์ชันจะมีความสมบูรณ์ยิ่งขึ้น แม้ว่าความสมบูรณ์จะอยู่ในเวอร์ชันก่อนๆ แต่ภาษาก็มีการปรับปรุงอย่างต่อเนื่องทั้งในด้านระเบียบวิธีและการนำไปปฏิบัติ คอลเลกชันใน Java ก็ไม่มีข้อยกเว้น กรอบงานคอลเลกชันหลักปรากฏใน J2SE 1.2 และได้รับการพัฒนาอย่างต่อเนื่อง โดยผ่านการเปลี่ยนแปลงที่น่าพึงพอใจมากกว่าน่าผิดหวัง ด้วยการเปิดตัว JDK 5 คอลเลกชันมีความสะดวก รวดเร็ว และง่ายต่อการทำงานมากขึ้น สิ่งนี้นำไปสู่ความจริงที่ว่าโปรแกรมเมอร์เริ่มใช้ประโยชน์จากพวกมันอย่างเข้มข้นมากขึ้น รูปแบบบางอย่างได้รับการพัฒนาสำหรับการทำงานร่วมกับสิ่งเหล่านี้ ซึ่งไม่ต้องสงสัยเลยว่ามีประสิทธิภาพ แต่ด้วย JDK 8 คอลเลกชันก็ดีขึ้นอีกครั้ง และดีขึ้นด้วยเธรด เห็นได้ชัดว่าเนื่องจากคอลเลกชันสามารถแสดงในรูปแบบของสตรีมวิธีการทำงานร่วมกับคอลเลกชันเหล่านั้นก็จะเปลี่ยนไปเช่นกัน ดังนั้น ฉันต้องการแสดงให้เห็นว่าโซลูชันที่คุ้นเคยและเข้าใจง่ายสำหรับคอลเลกชันนั้นง่ายยิ่งขึ้นเพียงใด
- ตัวอย่างที่ 1 ไม่มีอะไรจะง่ายกว่านี้อีกแล้ว
- ตัวอย่างที่ 2 ค้นหาค่าคู่ในรายการและแสดงในคอนโซล
- ตัวอย่างที่ 3 ลองนับจำนวนคำในรายการที่มีความยาว 5 ตัวอักษร
- ตัวอย่างที่ 4 พิมพ์คำที่ไม่ซ้ำ
- ตัวอย่างที่ 5 คำยาว
- ตัวอย่างที่ 6 คำที่มีตัวเลข
- ตัวอย่างที่ 7 การเลือกหมายเลข
ตัวอย่างที่ 1 ไม่มีอะไรจะง่ายกว่านี้อีกแล้ว
แน่นอนว่ามาเริ่มกันที่สิ่งที่ง่ายที่สุด มาดูองค์ประกอบทั้งหมดของคอลเลกชันและแสดงองค์ประกอบทั้งหมดกัน// создадим и заполним список
List<Integer> list = new ArrayList<>();
Collections.addAll(list, 1, 5, 6, 11, 3, 15, 7, 8);
// а теперь
// быстрый for по всем elementм, только для коллекций
for (Integer i:list){
System.out.println(i);
}
//но мы уже живем в JDK 8
//а значит нужно так
list.stream().forEach(System.out::println);
อย่างที่คุณสังเกตเห็น มีไวยากรณ์ใหม่ที่ในความคิดของฉันในฐานะมือใหม่ Java นั้นง่ายกว่ามาก ดังนั้นสิ่งที่มองเห็นได้ในไวยากรณ์ใหม่:
берем_список(list).превращаем_в_поток(stream).перебираем_все_элементы(forEach)(тут_интуитивно_понятно)
System.out::println
— ลิงก์ไปยังวิธีการแบบสแตติกที่ส่งออกสตริงไปยังคอนโซล แทนที่จะลิงก์ไปยังวิธีการแบบคงที่ คุณสามารถใช้รายการที่แตกต่างออกไปเล็กน้อยและไม่ชัดเจน:
list.stream().forEach(i -> System.out.println(i));
รายการนี้ใช้นิพจน์แลมบ์ดา ใช่แล้ว หากต้องการเรียนรู้วิธีทำงานกับสตรีม คุณจะต้องเรียนรู้สำนวนแลมบ์ดา ซึ่งมันวิเศษมาก นอกจากนี้ ฉันจะไม่แสดงวิธีการทำงานกับคอลเลกชันโดยใช้สตรีมเพียงอย่างเดียว โดยอาศัยข้อเท็จจริงที่ว่าคุณคุ้นเคยกับวิธีการแบบเดิมในระหว่างหลักสูตร
ตัวอย่างที่ 2 ค้นหาค่าคู่ในรายการและแสดงในคอนโซล
list.stream().filter(i -> i%2==0).forEach(System.out::println);
ปัญหาทั้งหมดได้รับการแก้ไขในบรรทัดเดียว ฉันหวังว่าคุณจะสนุกกับการทำงานในสายเดียว โดยใช้วิธีการนี้filter
เราได้กรองสตรีมและส่งออกสิ่งที่เหลืออยู่ในคอนโซล ตัวกรองเป็นสิ่งที่ทรงพลังมากซึ่งสามารถช่วยได้ในกรณีที่ไม่คาดคิดที่สุด มาสร้างสรรค์และเปลี่ยนแปลงเงื่อนไขของปัญหากันเถอะ ตัวอย่างเช่น เราต้องนับจำนวนเลขคู่ในรายการ:
long count = list.stream().filter(i -> i%2==0).count();
และอีกครั้งในบรรทัดเดียว บางอย่างก็ดูเรียบง่ายไปหมด ในตัวกรอง เราใช้นิพจน์แลมบ์ดา ดังนั้นจึงวางเฉพาะตัวเลขคู่ในสตรีมใหม่ จากนั้นนำไปใช้กับสตรีมใหม่count
ซึ่งนับจำนวนองค์ประกอบที่อยู่ในสตรีมใหม่
ตัวอย่างที่ 3 ลองนับจำนวนคำในรายการที่มีความยาว 5 ตัวอักษร
เราเล่นกับจำนวนเต็มแล้ว ทีนี้มาเล่นกับคำศัพท์กันดีกว่าList<String> list = new ArrayList<>();
Collections.addAll(list, "разые", "слова", "интересные", "And", "Not", "Very");
System.out.println(list.stream().filter(w -> w.length() == 5).count());
เราใช้ตัวกรองอีกครั้ง ในตัวกรอง โดยใช้นิพจน์แลมบ์ดา สตรีมใหม่จะแสดงขึ้น จากนั้นcount
ฉันก็คำนวณว่าสตรีมใหม่มีองค์ประกอบกี่องค์ประกอบ
ตัวอย่างที่ 4 พิมพ์คำที่ไม่ซ้ำ
งานที่คุ้นเคยเมื่อเราอ่านคำต่างๆ มากมายลงในคอลเลกชันจากไฟล์ และตอนนี้เราต้องการเพียงคำที่ไม่ซ้ำใครเท่านั้นList<String> list = new ArrayList<>();
Collections.addAll(list, "Vasya", "Таня", "Olya", "Vasya", "Olya", "Сергей");
list.stream().distinct().forEach(System.out::println);
การดำเนินการหลักเสร็จสิ้นบนสตรีมโดยใช้distinct
. ต่อไป ฉันขอแนะนำให้ดูงานบางอย่างของเราจากหลักสูตรโดยใช้ชุดข้อความ
ตัวอย่างที่ 5 คำยาว
ที่ระดับ 9 ของ Java Core ในการบรรยายที่ 11 มีปัญหาที่น่าสนใจในนั้นคุณต้องเขียนคำโดยคั่นด้วยเครื่องหมายจุลภาคใน File2 ซึ่งมีความยาวมากกว่า 6 อย่างเคร่งครัด ไม่ว่าคุณจะฟันดาบสวนประเภทใด ฉันเสนอวิธีแก้ปัญหาต่อไปนี้:-
จากไฟล์ต้นฉบับ เราจะอ่านคำทั้งหมดในรายการ
-
จากนั้นเราดำเนินการบรรทัดต่อไปนี้
Optional<String> rezult = list.stream() .filter(w->w.length()>6) .reduce((w1,w2)->w1+", "+w2);
-
result.get()
เขียนลงไฟล์
ตัวอย่างที่ 6 คำที่มีตัวเลข
เขียนคำทั้งหมดที่มีตัวเลข เช่น a1 หรือ abc3d โดยคั่นด้วยช่องว่างใน File2 นี่เป็นเงื่อนไขจากหนังสือปัญหาของเราเช่นกัน ดังที่คุณเดาไว้ วิธีแก้ปัญหานั้นง่ายมากOptional<String> rezult = list.stream()
.filter(w->w.matches(".*?\\d+.*?"))
.reduce((w1,w2)->w1+" "+w2);
เรากรองสตรีมโดยใช้นิพจน์ทั่วไป จากนั้นลดนิพจน์แลมบ์ดา เหมือนกับงานก่อนหน้านี้มาก
ตัวอย่างที่ 7 การเลือกหมายเลข
งานทั้งหมดมีลักษณะดังนี้:- อ่าน 2 ชื่อไฟล์จากคอนโซล
- ส่งออกตัวเลขทั้งหมดที่อยู่ในไฟล์แรกไปยังไฟล์ที่สอง
- ตัวเลขจะถูกคั่นด้วยช่องว่าง
- ปิดสตรีม.
Optional<String> rezult = list.stream().filter(w->w.matches("\\d+"))
.reduce((w1,w2)->w1+" "+w2);
System.out.println(rezult.get());
การใช้เธรดทำให้ปัญหาได้รับการแก้ไขด้วยวิธีที่ง่ายมาก แต่ดูเถิด เปรียบเทียบวิธีแก้ปัญหานี้กับสองวิธีก่อนหน้านี้ด้วยตัวคุณเอง สรุปบทความฉันต้องการสารภาพกับคุณ: พวกคุณฉันโกงเมื่อเลือกตัวอย่าง ความจริงก็คือฉันเลือกตัวอย่างที่ง่ายที่สุดเพื่อแสดงหัวข้อที่ไม่คุ้นเคยโดยใช้ปัญหาที่คุ้นเคย แน่นอนว่าเธรดนั้นใช้สำหรับทั้งงานที่เรียบง่ายและซับซ้อนมากขึ้น แต่ดังที่ Horstman เน้นย้ำในหนังสือของเขา “กระแสข้อมูลดำเนินการบนหลักการของ “อะไร ไม่ใช่อย่างไร” ซึ่งหมายความว่างานที่ซับซ้อนก่อนหน้านี้หลายอย่างจะง่ายขึ้น ฉันไม่รู้เกี่ยวกับคุณ แต่ฉันชอบกระแส ฉันหวังว่าฉันจะไม่กีดกันคุณจากการเรียนรู้สิ่งเหล่านั้น และให้ฉันอธิบายอีกเรื่องหนึ่ง:
- ฉันไม่ได้ตั้งใจที่จะสอนผู้อ่านถึงวิธีใช้สตรีมในคอลเลกชัน ฉันไม่ใช่ครูที่มีประสบการณ์ขนาดนั้น ฉันอยากจะแสดงให้คุณเห็นว่ากระทู้นั้นเรียบง่ายและน่าสนใจมาก! โดยทั่วไปนี่เป็นสิ่งจำเป็น
- ยิ่งฉันเข้าใจกระแสมากเท่าไร ฉันก็ยิ่งมองเห็นปัญหาที่พวกเขาแก้ไขปัญหาทั้งหมดจากหนังสือเรียนมากขึ้นเท่านั้น ซึ่งหมายความว่ากระแสนั้นไม่ได้ถูกประดิษฐ์ขึ้นโดยเปล่าประโยชน์
- สตรีมไม่เพียงแต่ใช้งานง่ายเท่านั้น แต่ยังมีข้อได้เปรียบที่สำคัญอีกด้วย เมื่อทำงานกับข้อมูลจำนวนมาก สตรีมมักจะมีประสิทธิภาพมากกว่า
GO TO FULL VERSION