Java Lambda Expressions เป็นคุณสมบัติใหม่ที่แนะนำโดย Java 8 พวกเขาสามารถกล่าวได้ว่าเป็นน้ำตาลไวยากรณ์สำหรับการเขียนโปรแกรมการทำงานจำลอง พวกเขาคล้ายกับการปิดใน JavaScript แต่พวกเขาค่อนข้างแตกต่างกัน วัตถุประสงค์หลักคือการจัดเตรียมไวยากรณ์การทำงานเพื่อทำให้การเข้ารหัสของเราง่ายขึ้น
Lambda Basic Symtax
โครงสร้างพื้นฐานของแลมบ์ดาคือ (ข้อโต้แย้ง) -> ร่างกายและมีหลายสถานการณ์:
ร่างกายจำเป็นต้องรวมข้อความที่มี {} และ {} สามารถละเว้นได้เมื่อมีคำสั่งเดียวเท่านั้น
วิธีการเขียนทั่วไปมีดังนี้:
(a) -> a * a
(int a, int b) -> a + b
(a, b) -> {return a - b;}
() -> system.out.println (thread.currentthread (). getId ())
functionalInterface
แนวคิด
นิพจน์ Java Lambda ขึ้นอยู่กับอินเทอร์เฟซที่ใช้งานได้ อินเทอร์เฟซที่ใช้งานได้คืออะไร? พูดง่ายๆคือมันเป็นอินเทอร์เฟซที่มีเพียงวิธีเดียว (ฟังก์ชั่น) จุดประสงค์ของอินเทอร์เฟซประเภทนี้สำหรับการดำเนินการเดียวซึ่งเทียบเท่ากับฟังก์ชั่นเดียว อินเทอร์เฟซทั่วไปเช่น runnable และ comparator เป็นอินเทอร์เฟซที่ใช้งานได้และมีคำอธิบายประกอบด้วย @functionalInterface
ยกตัวอย่าง
เป็นเรื่องง่ายที่จะเข้าใจโดยใช้เธรดเป็นตัวอย่าง อินเตอร์เฟส Runnable เป็นอินเทอร์เฟซที่ใช้กันทั่วไปเมื่อเราทำการเขียนโปรแกรมเธรดซึ่งรวมถึงวิธีการ void run () ซึ่งเป็นตรรกะการทำงานของเธรด ตามไวยากรณ์ก่อนหน้านี้เรามักจะใช้คลาสที่ไม่ระบุชื่อที่เรียกใช้เพื่อสร้างเธรดใหม่ดังนี้:
เธรดใหม่ (ใหม่ runnable () {@Override โมฆะสาธารณะ run () {system.out.println (thread.currentthread (). getId ());}}). start ();ถ้าคุณเขียนมากเกินไปมันไม่น่าเบื่อเหรอ? กฎการเขียนตามแลมบ์ดามีความกระชับและชัดเจนดังนี้:
เธรดใหม่ (() -> system.out.println (thread.currentthread (). getId ())). start ();
ให้ความสนใจกับพารามิเตอร์ของเธรด การใช้งานที่ไม่ระบุชื่อของ runnable ถูกนำมาใช้ในหนึ่งประโยคและมันถูกเขียนเป็นคำต่อไปนี้เพื่อให้เข้าใจได้ดีขึ้น
runnable r = () -> system.out.println (thread.currentthread (). getId ());
เธรดใหม่ (r). start ();
แน่นอนว่าจุดประสงค์ของแลมบ์ดาไม่เพียง แต่จะเขียนอย่างรัดกุม แต่เพื่อสรุปจุดประสงค์ระดับสูงขึ้นหลังจากทำความเข้าใจ
มาดูตัวอย่างอื่นของตัวเปรียบเทียบ ตามวิธีการเขียนแบบดั้งเดิมดังนี้:
จำนวนเต็ม [] a = {1, 8, 3, 9, 2, 0, 5}; arrays.sort (a, ตัวเปรียบเทียบใหม่ <จำนวนเต็ม> () {@Override int public Public (จำนวนเต็ม o1, จำนวนเต็ม O2) {return o1 - o2;}});นิพจน์แลมบ์ดาเขียนดังนี้:
จำนวนเต็ม [] a = {1, 8, 3, 9, 2, 0, 5};
array.sort (A, (O1, O2) -> O1 - O2);
อินเทอร์เฟซที่ใช้งานได้ใน JDK
เพื่อให้ไลบรารีคลาสที่มีอยู่ใช้การแสดงออกของแลมบ์ดาโดยตรงมีอินเทอร์เฟซบางส่วนใน Java 8 ที่ถูกทำเครื่องหมายว่าเป็นอินเตอร์เฟสการทำงาน:
มีการเพิ่มแพ็คเกจใหม่ java.util.function ลงใน Java 8 นำอินเทอร์เฟซการใช้งานที่ใช้กันทั่วไป:
นอกจากนี้ยังมีการเพิ่มฟังก์ชั่นที่เฉพาะเจาะจงมากขึ้นในการประมวลผลของประเภทพื้นฐานรวมถึง: booleansupplier, doubleBinaryOperator, doubleConsumer, doublefunction <r>, doublepredicate, doubleplier, doubletointfunction intsupplier, inttodoublefunction, inttolongfunction, intunaryoperator, longbinaryoperator, longconsumer, longfunction <r>, longpredicate, longsupplier, longtodoublefunction, longtointfunction, longunaryoperator todoubleFunction <t>, tointbifunction <t, u>, tointfunction <t>, tolongbifunction <t, u>, tolongfunction <t> เมื่อรวมกับอินเทอร์เฟซที่ใช้งานได้ด้านบนคุณสามารถเห็นบทบาทของอินเทอร์เฟซได้อย่างรวดเร็วผ่านชื่อคลาสของอินเทอร์เฟซการทำงานพื้นฐานเหล่านี้
สร้างอินเทอร์เฟซที่ใช้งานได้
บางครั้งเราจำเป็นต้องใช้อินเทอร์เฟซที่ใช้งานได้ด้วยตนเองและวิธีการนั้นง่ายมาก ก่อนอื่นคุณต้องตรวจสอบให้แน่ใจว่าอินเทอร์เฟซนี้สามารถมีการดำเนินการฟังก์ชั่นเดียวเท่านั้นจากนั้นหมายเหตุประกอบ @FunctionAlInterface บนประเภทอินเตอร์เฟส
ประเภทที่ได้มา
ประเภทการสืบทอดเป็นพื้นฐานของการแสดงออกของแลมบ์ดาและกระบวนการของประเภทการสืบทอดคือกระบวนการรวบรวมของนิพจน์แลมบ์ดา รหัสต่อไปนี้เป็นตัวอย่าง:
ฟังก์ชั่น <สตริง, จำนวนเต็ม> strToint = str -> integer.parseint (str);
ในระหว่างการรวบรวมกระบวนการของประเภทที่ได้มาที่ฉันเข้าใจมีดังนี้:
ประเภทเป้าหมายที่นี่คือคีย์และลายเซ็นของวิธีการผ่านประเภทเป้าหมายจากนั้นเปรียบเทียบกับนิพจน์แลมบ์ดา
วิธีการอ้างอิง
พื้นฐานของการอ้างอิงวิธีการ (การอ้างอิงวิธีการ) ยังเป็นอินเทอร์เฟซที่ใช้งานได้ซึ่งสามารถนำไปใช้โดยตรงเป็นอินเตอร์เฟสการทำงานมีฟังก์ชั่นเดียวกับการแสดงออกของแลมบ์ดาและขึ้นอยู่กับประเภทที่ได้มา การอ้างอิงวิธีการสามารถมองเห็นได้ง่ายขึ้นของนิพจน์แลมบ์ดาที่เรียกใช้วิธีเดียวเท่านั้น
ไวยากรณ์ที่อ้างอิงโดยวิธีการคือ: type :: methodName หรือ instancename :: methodName และชื่อวิธีที่สอดคล้องกับตัวสร้างใหม่
ตัวอย่างเช่นตัวอย่างที่ใช้ด้านบน:
ฟังก์ชั่น <สตริง, จำนวนเต็ม> strToint = str -> integer.parseint (str);
การอ้างอิงวิธีการที่สอดคล้องกันคือ
ฟังก์ชั่น <สตริง, จำนวนเต็ม> strToint = จำนวนเต็ม :: parseInt;
ตามประเภทของวิธีการอ้างอิงวิธีการส่วนใหญ่แบ่งออกเป็นประเภทต่อไปนี้: การอ้างอิงวิธีการสร้างการอ้างอิงวิธีการแบบสแตติก, การอ้างอิงวิธีการอินสแตนซ์ในอินสแตนซ์, การอ้างอิงวิธีการอินสแตนซ์เกี่ยวกับประเภท ฯลฯ
การอ้างอิงวิธีการสร้าง
ไวยากรณ์คือ: พิมพ์ :: ใหม่ ตัวอย่างเช่นฟังก์ชั่นต่อไปนี้คือการแปลงสตริงเป็นอาร์เรย์
การเขียนอ้างอิงวิธีการ
ฟังก์ชั่น <สตริง, จำนวนเต็ม> strToint = จำนวนเต็ม :: ใหม่;
การเขียนแลมบ์ดา
ฟังก์ชั่น <สตริง, จำนวนเต็ม> strToint = str -> ใหม่จำนวนเต็ม (str);
การเขียนแบบดั้งเดิม
ฟังก์ชั่น <สตริง, จำนวนเต็ม> strToint = ฟังก์ชั่นใหม่ <สตริง, จำนวนเต็ม> () {@Override สาธารณะจำนวนเต็มใช้ (สตริง str) {ส่งคืนจำนวนเต็มใหม่ (str); -
การอ้างอิงตัวสร้างอาร์เรย์
ไวยากรณ์คือ: พิมพ์ [] :: ใหม่ ตัวอย่างเช่นฟังก์ชั่นต่อไปนี้คือการสร้างสตริงอาร์เรย์ของความยาวที่ระบุ
การเขียนอ้างอิงวิธีการ
ฟังก์ชั่น <จำนวนเต็ม, สตริง []> impedArray = string [] :: ใหม่;
การเขียนอ้างอิงวิธีการ
ฟังก์ชั่น <จำนวนเต็ม, สตริง []> iscentArray = ความยาว -> สตริงใหม่ [ความยาว];
การเขียนแบบดั้งเดิม
ฟังก์ชั่น <จำนวนเต็ม, สตริง []> impedArray = ฟังก์ชั่นใหม่ <จำนวนเต็ม, สตริง []> () {@Override สตริงสาธารณะ [] ใช้ (ความยาวจำนวนเต็ม) {ส่งคืนสตริงใหม่ [ความยาว]; -การอ้างอิงวิธีการคงที่
ไวยากรณ์คือ: พิมพ์ :: ใหม่ เนื่องจากฟังก์ชั่นต่อไปนี้ยังใช้ในการแปลงสตริงเป็นอาร์เรย์
การเขียนอ้างอิงวิธีการ
ฟังก์ชั่น <สตริง, จำนวนเต็ม> strToint = จำนวนเต็ม :: parseInt;
การเขียนแลมบ์ดา
ฟังก์ชั่น <สตริง, จำนวนเต็ม> strToint = str -> integer.parseint (str);
การเขียนแบบดั้งเดิม
ฟังก์ชั่น <สตริง, จำนวนเต็ม> strToint = ฟังก์ชั่นใหม่ <สตริง, จำนวนเต็ม> () {@Override Public Public Integer ใช้ (String str) {return integer.parseint (str); -การอ้างอิงวิธีการอินสแตนซ์บนอินสแตนซ์
ไวยากรณ์คือ: Instancename :: MethodName ตัวอย่างเช่นฟังก์ชั่นการตัดสินต่อไปนี้ใช้เพื่อพิจารณาว่าชื่อที่กำหนดมีอยู่ในรายการ
รายการ <String> ชื่อ = array.aslist (สตริงใหม่ [] {"จางซาน", "li si", "wang wu"});
Predicate <String> checkNameExists = ชื่อ :: มี;
System.out.println (ChecknameExists.test ("Zhang San"));
System.out.println (ChecknameExists.test ("Zhang Si"));
การอ้างอิงวิธีการอินสแตนซ์เกี่ยวกับประเภท
ไวยากรณ์คือ: type :: methodname การอ้างอิงรันไทม์หมายถึงวัตถุในบริบทเช่นฟังก์ชันด้านล่างเพื่อส่งคืนความยาวของสตริง
ฟังก์ชั่น <สตริง, จำนวนเต็ม> calcstrLength = string :: length; system.out.println (calcstrlength.apply ("จางซาน")); รายการ <string> ชื่อ = array.aslist (สตริงใหม่ [] {"zhangsan", "lisi", "wangwu"};
ตัวอย่างเช่นฟังก์ชั่นต่อไปนี้ได้ระบุตัวคั่นเพื่อแยกสตริงออกเป็นอาร์เรย์
bifunction <string, string, string []> split = string :: split;
String [] names = split.apply ("Zhangsan, Lisi, Wangwu", ",");
System.out.println (array.toString (ชื่อ));
สตรีมวัตถุ
แนวคิด
สตรีมคืออะไร? สตรีมที่นี่แตกต่างจาก inputstream และ outputstream ใน IO สตรีมตั้งอยู่ในแพ็คเกจ java.util.stream และยังถูกเพิ่มเข้ามาใหม่ใน Java 8. สตรีมเป็นเพียงชุดขององค์ประกอบที่รองรับการดำเนินการรวมแบบขนานแบบอนุกรมซึ่งสามารถเข้าใจได้ว่าเป็นเวอร์ชันที่ได้รับการปรับปรุงของคอลเลกชันหรือตัววนซ้ำ การดำเนินการรวมคืออะไร? เพื่อยกตัวอย่างง่าย
คุณสมบัติหลายอย่างของสตรีม:
การประมวลผลเดียว หลังจากการประมวลผลหนึ่งเสร็จสิ้นสตรีมปัจจุบันจะถูกปิด
สนับสนุนวิธีการทั่วไปในการรับกระแสในการดำเนินการแบบขนาน
รับจากคอลเลกชัน
collection.stream ();
collection.parallelsstream ();
โรงงานคงที่
array.stream (อาร์เรย์)
Stream.of (t …)
intstream.Range ()
ที่นี่เราจะให้คำแนะนำสั้น ๆ เกี่ยวกับสตรีมและจะมีแอปพลิเคชันเฉพาะด้านล่าง หากคุณต้องการพูดคุยเกี่ยวกับความสัมพันธ์ระหว่างการแสดงออกของสตรีมและแลมบ์ดาไม่มีความสัมพันธ์ใกล้ชิดโดยเฉพาะ เป็นเพียงการแสดงออกของแลมบ์ดาที่อำนวยความสะดวกในการใช้สตรีมอย่างมาก หากไม่มีการแสดงออกของแลมบ์ดาจะมีการสร้างคลาสที่ไม่ระบุชื่อจำนวนมากในระหว่างการใช้สตรีมซึ่งเป็นเรื่องที่น่าอึดอัดใจมาก
ยกตัวอย่าง
การสาธิตต่อไปนี้ขึ้นอยู่กับวัตถุของพนักงานและวัตถุรายการที่ประกอบด้วยวัตถุพนักงาน
พนักงานชั้นเรียนสาธารณะ {ชื่อสตริงส่วนตัว; เซ็กซ์สตริงส่วนตัว; อายุ int ส่วนตัว; พนักงานสาธารณะ (ชื่อสตริง, String Sex, อายุ int) {super (); this.name = ชื่อ; this.sex = เพศ; this.age = อายุ; } สตริงสาธารณะ getName () {ชื่อคืน; } Public String getSex () {return sex; } public int getage () {return Age; } @Override สตริงสาธารณะ toString () {stringBuilder builder = new StringBuilder (); builder.append ("พนักงาน {name ="). ต่อ (ชื่อ) .append (", sex ="). ผนวก (เพศ) .append (", age ="). ผนวก (อายุ) .append ("}"); return builder.toString (); }} รายการ <Spop อยู่> พนักงาน = new ArrayList <> (); พนักงาน ADD (พนักงานใหม่ ("จางซาน", "ชาย", 25)); พนักงาน ADD (พนักงานใหม่ ("Li Si", "Female", 24)); พนักงาน ADD (พนักงานใหม่ ("วังวู", "หญิง", 23)); พนักงาน. ADD (พนักงานใหม่ ("วันเสาร์", "ชาย", 22)); พนักงาน. ADD (พนักงานใหม่ ("Sun Qi", "Female", 21)); Addd (พนักงานใหม่ (พิมพ์พนักงานทั้งหมด
คอลเลกชันให้วิธีการ foreach สำหรับเราในการใช้งานวัตถุแต่ละรายการทีละคน
พนักงาน. foreach (e -> system.out.println (e));
หรือ
พนักงานสตรีม (). foreach (e -> system.out.println (e));
เรียงตามอายุ
collections.sort (พนักงาน, (e1, e2) -> e1.getage () - e2.getage ());
พนักงาน. foreach (e -> system.out.println (e));
หรือ
พนักงานสตรีม (). เรียงลำดับ ((e1, e2) -> e1.getage () -e2.getage ()). foreach (e -> system.out.println (e));
พิมพ์พนักงานหญิงที่เก่าแก่ที่สุด
สูงสุด/นาทีส่งคืนองค์ประกอบที่ใหญ่ที่สุด/นาทีภายใต้เงื่อนไขการเรียงลำดับที่ระบุ
พนักงาน maxagefemaleemployee = พนักงานสตรีม () .filter (e -> "หญิง" .Equals (e.getsex ())) .max ((e1, e2) -> e1.getage () -e2.getage ()) .get (); system.out.println
พิมพ์พนักงานชายที่มีอายุมากกว่า 20 ปี
กรององค์ประกอบที่ตรงตามเกณฑ์
พนักงานสตรีม ()
.filter (e -> e.getage ()> 20 && "ชาย". เท่า equals (e.getsex ())))
. foreach (e -> system.out.println (e));
พิมพ์พนักงานชายสองคนที่เก่าแก่ที่สุด
วิธีการ จำกัด การสกัดกั้นองค์ประกอบที่ จำกัด
พนักงาน. สตรีม () .filter (e -> "ชาย" .Equals (e.getSex ())) .sorted ((e1, e2) -> e2.getage () -e1.getage ()) .limit (2). foreach (e -> system.out.println
พิมพ์ชื่อของพนักงานชายทุกคนใช้แยกต่างหาก
แผนที่เพื่อสร้างสตรีมใหม่หลังจากดำเนินการฟังก์ชั่นที่กำหนด
String maleemployeesnames = stompowion.stream () .map (e -> e.getName ()) .collect (collectors.joining (",")); system.out.println (maleemployeesnames);ข้อมูลทางสถิติ
IntsummaryStatistics, DoublesummarmaryStatistics, LongsummaryStatistics มีข้อมูลสรุปในสตรีม
IntsummaryStatistics stat = พนักงานสตรีม () .maptoint (พนักงาน :: getage) .summarystatistics (); system.out.println ("จำนวนพนักงานทั้งหมด:" + stat.getCount ()); system.out.println ("อายุสูงสุด:" stat.getMin ()); System.out.println ("อายุเฉลี่ย:" + stat.getAverage ());สรุป
นิพจน์แลมบ์ดาสามารถลดรหัสได้มากและปรับปรุงประสิทธิภาพการทำงาน แน่นอนว่ามีข้อเสียนั่นคือการแสดงออกที่ซับซ้อนจะอ่านได้ไม่ดีหรืออาจเป็นเพราะพวกเขาไม่คุ้นเคยกับมัน ถ้าคุณชินกับมันฉันเชื่อว่าคุณจะชอบมัน ทุกอย่างมีสองด้านขึ้นอยู่กับว่าเราสมดุลข้อดีข้อเสียโดยเฉพาะอย่างยิ่งในทีม
ข้างต้นคือข้อมูลที่คัดแยก Java8 Javalambda เราจะยังคงเพิ่มข้อมูลที่เกี่ยวข้องในอนาคต ขอบคุณสำหรับการสนับสนุนเว็บไซต์นี้!