คำนำ: Java 8 ได้รับการปล่อยตัวมาระยะหนึ่งแล้วและสัญญาณทั้งหมดบ่งชี้ว่า Java 8 เป็นการเปลี่ยนแปลงที่สำคัญในการกระจาย มีบทความมากมายเกี่ยวกับรหัส Java ที่แนะนำคุณสมบัติใหม่ของ Java 8 เช่นการเล่นกับ Java 8 Lambdas และพร้อมกัน, Java 8 Date Time Tutorial: LocalDateTime และ Abstract Class เมื่อเทียบกับอินเตอร์เฟสใน JDK 8 ERA บทความนี้ยังหมายถึงข้อมูลอื่น ๆ เช่น: 15 ต้องอ่านบทเรียน Java 8 และด้านมืดของ Java 8 บทความนี้ได้รวบรวมข้อมูลข้างต้นและรวบรวมไว้ในตำราอ้างอิงเกี่ยวกับคุณสมบัติใหม่ของ Java 8 ฉันหวังว่าคุณจะได้รับบางสิ่งบางอย่าง
1. บทนำ
ไม่ต้องสงสัยเลยว่า Java 8 เป็นรุ่นที่สำคัญที่สุดของ Java ตั้งแต่ Java 5 (เปิดตัวในปี 2004) รุ่นนี้มีคุณสมบัติใหม่มากกว่าหนึ่งโหลในภาษาคอมไพเลอร์ไลบรารีเครื่องมือและ JVM ในบทความนี้เราจะได้เรียนรู้คุณสมบัติใหม่เหล่านี้และใช้ตัวอย่างที่เป็นประโยชน์เพื่อแสดงให้เห็นว่าสถานการณ์ใดที่เหมาะสมสำหรับการใช้งาน
บทช่วยสอนนี้มีปัญหาหลายประเภทที่นักพัฒนา Java มักจะเผชิญ:
ภาษา
ผู้ประกอบการ
ห้องสมุด
เครื่องมือ
รันไทม์ (JVM)
2. คุณสมบัติใหม่ของภาษา Java
Java 8 เป็น Java รุ่นสำคัญ บางคนเชื่อว่าแม้ว่านักพัฒนา Java จะคาดหวังคุณสมบัติใหม่เหล่านี้ แต่ก็ต้องใช้ความพยายามอย่างมากในการเรียนรู้ ในส่วนนี้เราจะแนะนำคุณสมบัติใหม่ส่วนใหญ่ของ Java 8
2.1 นิพจน์แลมบ์ดาและอินเทอร์เฟซการทำงาน
Lambda Expressions (หรือที่เรียกว่าการปิด) เป็นการเปลี่ยนแปลงภาษาที่ใหญ่ที่สุดและคาดการณ์ไว้มากที่สุดใน Java 8 มันช่วยให้เราสามารถส่งฟังก์ชั่นเป็นพารามิเตอร์ไปยังวิธีการหรือประมวลผลรหัสเป็นข้อมูล: นักพัฒนาที่ใช้งานได้คุ้นเคยกับแนวคิดเหล่านี้มาก หลายภาษาบนแพลตฟอร์ม JVM (Groovy, Scala ฯลฯ ) ได้สนับสนุนการแสดงออกของแลมบ์ดาตั้งแต่เกิด แต่นักพัฒนา Java ไม่มีทางเลือกนอกจากใช้ชั้นเรียนภายในที่ไม่ระบุชื่อแทนการแสดงออกของแลมบ์ดา
การออกแบบของแลมบ์ดาใช้เวลานานมากและความพยายามของชุมชนมากมายและในที่สุดก็พบว่าโซลูชันการใช้งานประนีประนอมที่สามารถบรรลุโครงสร้างภาษาที่เรียบง่ายและกะทัดรัด นิพจน์แลมบ์ดาที่ง่ายที่สุดสามารถประกอบด้วยรายการพารามิเตอร์ที่คั่นด้วยเครื่องหมายจุลภาค -> สัญลักษณ์และบล็อกคำสั่งเช่น:
array.aslist ("A", "B", "D") .Foreach (e -> system.out.println (e));
ในรหัสข้างต้นประเภทของพารามิเตอร์ E นั้นได้มาจากการใช้เหตุผลของคอมไพเลอร์และคุณยังสามารถระบุประเภทของพารามิเตอร์ได้อย่างชัดเจนเช่น:
array.aslist ("A", "B", "D") .Foreach ((String E) -> System.out.println (e));
หากนิพจน์แลมบ์ดาต้องการบล็อกคำสั่งที่ซับซ้อนมากขึ้นคุณสามารถแนบบล็อกคำสั่งด้วยวงเล็บปีกกาซึ่งคล้ายกับร่างกายของฟังก์ชั่นใน Java ตัวอย่างเช่น:
array.aslist ("A", "B", "D") .Foreach (e -> {System.out.print (e); System.out.print (e);});นิพจน์แลมบ์ดาสามารถอ้างถึงสมาชิกชั้นเรียนและตัวแปรท้องถิ่น (ซึ่งจะแปลงตัวแปรเหล่านี้โดยปริยายเป็นขั้นสุดท้าย) ตัวอย่างเช่นสองบล็อกรหัสต่อไปนี้มีเอฟเฟกต์เดียวกัน:
String separator = ","; array.aslist ("A", "B", "D") .Foreach ((String E) -> System.out.print (e + separator));และ
ตัวคั่นสตริงสุดท้าย = ","; array.aslist ("a", "b", "d"). foreach ((สตริง e) -> system.out.print (e + ตัวคั่น));นิพจน์แลมบ์ดามีค่าส่งคืนและประเภทของค่าส่งคืนนั้นได้มาจากการอนุมานคอมไพเลอร์ หากบล็อกคำสั่งในนิพจน์แลมบ์ดามีเพียงบรรทัดเดียวคุณไม่จำเป็นต้องใช้คำสั่ง Return ตัวอย่างสองรหัสต่อไปนี้มีเอฟเฟกต์เดียวกัน:
array.aslist ("A", "B", "D") .Sort ((E1, E2) -> E1.Compareto (E2));และ
array.aslist ("a", "b", "d") .sort ((e1, e2) -> {int result = e1.Compareto (e2); ผลตอบแทน;});เพื่อให้ฟังก์ชั่นที่มีอยู่เข้ากันได้ดีกับการแสดงออกของแลมบ์ดานักออกแบบแลมบ์ดาจึงพิจารณาวิธีการมากมายดังนั้นพวกเขาจึงมาพร้อมกับแนวคิดของอินเทอร์เฟซฟังก์ชั่น ฟังก์ชั่นอินเทอร์เฟซหมายถึงอินเทอร์เฟซที่มีฟังก์ชั่นเดียวเท่านั้นและอินเทอร์เฟซดังกล่าวสามารถแปลงเป็นนิพจน์แลมบ์ดาโดยปริยาย java.lang.runnable และ java.util.concurrent.callable เป็นตัวอย่างที่ดีที่สุดของอินเทอร์เฟซการทำงาน ในทางปฏิบัติอินเทอร์เฟซการทำงานมีความเปราะบางมาก: ตราบใดที่นักพัฒนาเพิ่มฟังก์ชั่นลงในอินเทอร์เฟซอินเตอร์เฟสจะไม่เป็นอินเตอร์เฟสที่ใช้งานได้อีกต่อไปทำให้เกิดความล้มเหลวในการรวบรวม เพื่อที่จะเอาชนะช่องโหว่ระดับรหัสนี้และระบุอย่างชัดเจนว่าอินเทอร์เฟซเป็นอินเทอร์เฟซที่ใช้งานได้ Java 8 ให้คำอธิบายประกอบพิเศษ @functionalInterface (อินเทอร์เฟซที่เกี่ยวข้องทั้งหมดในไลบรารี Java มีคำอธิบายประกอบนี้) เพื่อให้คำจำกัดความง่าย ๆ ของอินเทอร์เฟซการทำงาน:
@functionalInterface อินเตอร์เฟสสาธารณะฟังก์ชั่น {โมฆะวิธี ();}อย่างไรก็ตามสิ่งหนึ่งที่ควรทราบคือวิธีการเริ่มต้นและวิธีการคงที่จะไม่ทำลายคำจำกัดความของอินเทอร์เฟซการทำงานดังนั้นรหัสต่อไปนี้จึงถูกกฎหมาย
@functionalInterface อินเตอร์เฟสสาธารณะ functionaldefaultmethods {void method (); เป็นโมฆะเริ่มต้น defaultMethod () {}}Lambda Expressions ซึ่งเป็นจุดขายที่ใหญ่ที่สุดของ Java 8 มีศักยภาพที่จะดึงดูดนักพัฒนาซอฟต์แวร์ให้เข้าร่วมแพลตฟอร์ม JVM มากขึ้นและใช้แนวคิดของการเขียนโปรแกรมที่ใช้งานได้ในการเขียนโปรแกรม Java บริสุทธิ์ หากคุณต้องการทราบข้อมูลเพิ่มเติมเกี่ยวกับการแสดงออกของแลมบ์ดาคุณสามารถอ้างถึงเอกสารอย่างเป็นทางการ
2.2 วิธีการเริ่มต้นและแบบคงที่ของอินเทอร์เฟซ
Java 8 ใช้แนวคิดใหม่สองแนวคิดเพื่อขยายความหมายของอินเทอร์เฟซ: วิธีเริ่มต้นและวิธีการคงที่ วิธีการเริ่มต้นทำให้อินเทอร์เฟซคล้ายกับลักษณะ แต่เป้าหมายที่จะบรรลุนั้นแตกต่างกัน วิธีการเริ่มต้นอนุญาตให้นักพัฒนาเพิ่มวิธีการใหม่ไปยังอินเทอร์เฟซที่มีอยู่โดยไม่ทำลายความเข้ากันได้ของไบนารีนั่นคือไม่ใช่การบังคับให้คลาสที่ใช้อินเทอร์เฟซเพื่อใช้วิธีการที่เพิ่มขึ้นใหม่ในเวลาเดียวกัน
ความแตกต่างระหว่างวิธีการเริ่มต้นและวิธีการนามธรรมคือต้องใช้วิธีนามธรรมในขณะที่วิธีการเริ่มต้นไม่ได้ วิธีการเริ่มต้นที่จัดทำโดยอินเทอร์เฟซจะได้รับการสืบทอดหรือเขียนทับโดยคลาสการใช้งานอินเตอร์เฟส รหัสตัวอย่างมีดังนี้:
อินเทอร์เฟซส่วนตัว defaulable {// อินเทอร์เฟซตอนนี้อนุญาตให้ใช้วิธีเริ่มต้นผู้ใช้อาจหรือ // อาจไม่ใช้ (แทนที่) สตริงเริ่มต้น notrequired () {return "การใช้งานเริ่มต้น"; }} คลาสคงที่คลาสคงที่เริ่มต้นได้ emplements defaulable {} คลาสคงที่คลาสคงที่ overridableImpl ใช้ defaulable {@Override สตริงสาธารณะ notrequired () {returnอินเทอร์เฟซ defaulable ใช้คำหลักเริ่มต้นเพื่อกำหนดวิธีเริ่มต้น notrequired () คลาส defaultableImpl ใช้อินเทอร์เฟซนี้และสืบทอดวิธีเริ่มต้นในอินเทอร์เฟซนี้โดยค่าเริ่มต้น คลาส OverridableIMPL ยังใช้อินเทอร์เฟซนี้ แต่แทนที่วิธีเริ่มต้นของอินเทอร์เฟซและให้การใช้งานที่แตกต่างกัน
คุณสมบัติที่น่าสนใจอีกอย่างที่นำโดย Java 8 คือวิธีการคงที่สามารถกำหนดในอินเทอร์เฟซ รหัสตัวอย่างมีดังนี้:
อินเทอร์เฟซส่วนตัว defaulableFactory {// อินเทอร์เฟซตอนนี้อนุญาตวิธีการคงที่แบบคงที่ defaulable สร้าง (ซัพพลายเออร์ <Defaulable> ซัพพลายเออร์) {return supplier.get ();}}ตัวอย่างโค้ดต่อไปนี้รวมสถานการณ์การใช้งานของวิธีการเริ่มต้นและวิธีการคงที่:
โมฆะคงที่สาธารณะหลัก (สตริง [] args) {defaulaable default = defaulablefactory.create (defaultableImpl :: ใหม่); system.out.println (เริ่มต้นได้ผลลัพธ์ของรหัสนี้มีดังนี้:
การใช้งานเริ่มต้น
การใช้งานที่ถูกแทนที่
เนื่องจากการใช้วิธีเริ่มต้นบน JVM ให้การสนับสนุนในระดับไบต์จึงมีประสิทธิภาพมาก วิธีการเริ่มต้นอนุญาตให้มีการปรับปรุงอินเตอร์เฟสโดยไม่ทำลายระบบการสืบทอดที่มีอยู่ แอปพลิเคชั่นของคุณลักษณะนี้ในไลบรารีอย่างเป็นทางการคือ: เพิ่มวิธีการใหม่ในอินเตอร์เฟส java.util.collection เช่น stream (), parallelsStream (), foreach () และ removeif () ฯลฯ ฯลฯ
แม้ว่าวิธีการเริ่มต้นมีประโยชน์มากมาย แต่ควรใช้ด้วยความระมัดระวังในการพัฒนาจริง: ในระบบการสืบทอดที่ซับซ้อนวิธีการเริ่มต้นอาจทำให้เกิดข้อผิดพลาดที่คลุมเครือและการรวบรวมข้อผิดพลาด หากคุณต้องการทราบรายละเอียดเพิ่มเติมโปรดดูเอกสารอย่างเป็นทางการ
2.3 การอ้างอิงวิธีการ
การอ้างอิงวิธีการอนุญาตให้นักพัฒนาอ้างอิงวิธีการที่มีอยู่โดยตรงตัวสร้างคลาส Java หรือวัตถุอินสแตนซ์ การอ้างอิงวิธีการและการแสดงออกของแลมบ์ดาใช้ร่วมกันทำให้ตัวสร้างของคลาส Java ดูกะทัดรัดและกระชับโดยไม่มีรหัสเทมเพลตที่ซับซ้อนจำนวนมาก
ในตัวอย่างของ Simon คลาสรถเป็นตัวอย่างของการอ้างอิงวิธีการที่แตกต่างกันซึ่งสามารถช่วยให้ผู้อ่านแยกแยะความแตกต่างระหว่างการอ้างอิงวิธีการสี่ประเภท
รถคลาสสแตติกสาธารณะ {รถสแตติกสาธารณะสร้าง (ซัพพลายเออร์สุดท้าย <sar> ซัพพลายเออร์) {ส่งคืนซัพพลายเออร์ get ();} เพื่อนร่วมงานโมฆะคงที่สาธารณะ (รถคันสุดท้าย) {system.out.out.println ("ชนกัน" + car.toString (); {system.out.println ("ซ่อมแซม" + this.toString ());}}ประเภทของการอ้างอิงสำหรับวิธีแรกคือการอ้างอิงตัวสร้างไวยากรณ์คือคลาส :: รูปแบบทั่วไปใหม่หรือมากกว่า: คลาส <t> :: ใหม่ หมายเหตุ: ตัวสร้างนี้ไม่มีพารามิเตอร์
รถคันสุดท้าย = car.create (Car :: ใหม่); รายการสุดท้าย <sar> cars = array.aslist (Car);
ประเภทของการอ้างอิงของวิธีที่สองคือการอ้างอิงวิธีการคงที่และไวยากรณ์คือคลาส :: static_method หมายเหตุ: วิธีนี้ยอมรับพารามิเตอร์ประเภทรถยนต์
cars.foreach (car :: collide);
วิธีที่สามอ้างอิงถึงประเภทคือการอ้างอิงถึงวิธีการสมาชิกของคลาสที่แน่นอนและไวยากรณ์คือเมธอดคลาส :: โปรดทราบว่าวิธีนี้ไม่ได้กำหนดพารามิเตอร์:
cars.foreach (รถ :: ซ่อม);
วิธีการอ้างอิงวิธีที่สี่คือการอ้างอิงถึงวิธีการสมาชิกของวัตถุอินสแตนซ์และไวยากรณ์คืออินสแตนซ์ :: เมธอด หมายเหตุ: วิธีนี้ยอมรับพารามิเตอร์ประเภทรถยนต์:
รถตำรวจสุดท้าย = car.create (car :: new); cars.foreach (ตำรวจ :: ติดตาม);
เรียกใช้ตัวอย่างด้านบนและคุณสามารถดูผลลัพธ์ต่อไปนี้ในคอนโซล (อินสแตนซ์รถยนต์อาจแตกต่างกัน):
com.javacodegeeks.java8.method.erferences.methodreferences$car@7a81197d ซ่อมแซม com.javacodegekeks.java8.method.references.methodreferences$car@7a81197d com.javacodegeeks.java8.method.references.methodreferences$car@7a81197d
หากคุณต้องการทำความเข้าใจและเรียนรู้เนื้อหาที่มีรายละเอียดเพิ่มเติมคุณสามารถอ้างอิงเอกสารอย่างเป็นทางการ
2.4 ซ้ำความคิดเห็น
นับตั้งแต่การเปิดตัวคำอธิบายประกอบใน Java 5 คุณลักษณะนี้ได้รับความนิยมอย่างมากและมีการใช้กันอย่างแพร่หลายในกรอบและโครงการต่างๆ อย่างไรก็ตามคำอธิบายประกอบมีข้อ จำกัด ที่ยิ่งใหญ่: ไม่สามารถใช้คำอธิบายประกอบเดียวกันได้หลายครั้งในสถานที่เดียวกัน Java 8 แบ่งข้อ จำกัด นี้และแนะนำแนวคิดของคำอธิบายประกอบซ้ำซึ่งช่วยให้คำอธิบายประกอบเดียวกันนี้ใช้หลายครั้งในสถานที่เดียวกัน
การกำหนดคำอธิบายประกอบซ้ำ ๆ ใน Java 8 โดยใช้คำอธิบายประกอบ @repeatable จริง ๆ แล้วไม่ใช่การปรับปรุงระดับภาษา แต่เป็นเคล็ดลับที่ทำโดยคอมไพเลอร์และเทคโนโลยีพื้นฐานยังคงเหมือนเดิม คุณสามารถใช้รหัสต่อไปนี้เพื่ออธิบาย:
แพ็คเกจ com.javacodegeeks.java8.repeatable.annotations; นำเข้า java.lang.annotation.ElementType; นำเข้า java.lang.annotation.Repeatable; นำเข้า java.lang.annotation.retention; นำเข้า java.lang.annotation.RetentionPolicy; นำเข้า java.lang.annotation.target; การทำซ้ำคลาสสาธารณะ {@target (elementtype.type) @retention (RetentionPolicy.runtime) ตัวกรอง @Interface สาธารณะ {ตัวกรอง [] ค่า ();} @Target (ElementType.type) @Retention @Filter ("Filter1") @Filter ("Filter2") อินเตอร์เฟสสาธารณะตัวกรอง {} โมฆะคงที่สาธารณะหลัก (สตริง [] args) {สำหรับ (ตัวกรองตัวกรอง: filterable.class.getannotationsByType (filter.class)) {system.out.printlnอย่างที่เราเห็นคลาสตัวกรองที่นี่ใช้คำอธิบายประกอบ @repeatable (filters.class) และตัวกรองเป็นคอนเทนเนอร์ที่เก็บคำอธิบายประกอบตัวกรอง คอมไพเลอร์พยายามบล็อกรายละเอียดเหล่านี้จากนักพัฒนา ด้วยวิธีนี้อินเทอร์เฟซที่กรองได้สามารถใส่คำอธิบายประกอบด้วยคำอธิบายประกอบตัวกรองสองรายการ (ไม่มีข้อมูลเกี่ยวกับตัวกรองที่กล่าวถึงที่นี่)
นอกจากนี้ Reflection API ยังมีวิธีการใหม่: getAnnotationsByType () ซึ่งสามารถส่งคืนคำอธิบายประกอบซ้ำของประเภทที่แน่นอนเช่น
Filter.class.getannoation (filters.class) จะส่งคืนสองอินสแตนซ์ตัวกรองและเอาต์พุตเนื้อหาไปยังคอนโซลมีดังนี้:
ตัวกรอง 1
ตัวกรอง 2
หากคุณต้องการทราบข้อมูลเพิ่มเติมคุณสามารถอ้างถึงเอกสารอย่างเป็นทางการ
2.5 การอนุมานประเภทที่ดีกว่า
คอมไพเลอร์ Java 8 ได้ทำการปรับปรุงอย่างมากในการอนุมานประเภท ในหลาย ๆ สถานการณ์คอมไพเลอร์สามารถอนุมานประเภทข้อมูลของพารามิเตอร์ที่แน่นอนทำให้รหัสกระชับมากขึ้น รหัสตัวอย่างมีดังนี้:
แพ็คเกจ com.javacodegeeks.java8.type.inference; ค่าคลาสสาธารณะ <t> {สาธารณะคงที่ <t> t defaultValue () {return null; } สาธารณะ t getOrdefault (ค่า t, t defaultValue) {return (value! = null)? ค่า: defaultValue;}}รหัสต่อไปนี้เป็นแอปพลิเคชันของค่าประเภท <string>::
แพ็คเกจ com.javacodegeeks.java8.type.inference; คลาสสาธารณะ typeinference {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {ค่าสุดท้าย <string> value = ค่าใหม่ <> (); value.getOrdefault ("22", value.defaultValue ());}}ประเภทของค่าพารามิเตอร์ defaultValue () มาจากคอมไพเลอร์และไม่จำเป็นต้องระบุอย่างชัดเจน ใน Java 7 รหัสนี้จะมีข้อผิดพลาดในการรวบรวมเว้นแต่จะใช้ค่า <string> defaultValue ()
2.6 ขยายสถานการณ์แอปพลิเคชันของคำอธิบายประกอบ
Java 8 ขยายสถานการณ์แอปพลิเคชันของคำอธิบายประกอบ ตอนนี้คำอธิบายประกอบสามารถใช้กับเกือบทุกองค์ประกอบ: ตัวแปรท้องถิ่นประเภทอินเตอร์เฟส superclasses และคลาสการใช้งานอินเตอร์เฟสและแม้แต่คำจำกัดความข้อยกเว้นของฟังก์ชั่น นี่คือตัวอย่างบางส่วน:
แพ็คเกจ com.javacodegeeks.java8.annotations; นำเข้า java.lang.annotation.ElementType; นำเข้า java.lang.annotation.retention; นำเข้า java.lang.annotation.RetentionPolicy; นำเข้า java.lang.annotation.target; นำเข้า java.util.arraylist; นำเข้า Java.util.Collection; คำอธิบายประกอบชั้นเรียนสาธารณะ {@retention (RetentionPolicy.runtime) @Target ({ElementType.type_use, ElementType.type_Parameter}) สาธารณะ @interface nonempty {} ผู้ถือคลาสคงที่ @suppresswarnings ("ไม่ได้ใช้") โมฆะคงที่สาธารณะหลัก (สตริง [] args) {ผู้ถือสุดท้าย <string> holder = new @NonEmpty Holder <String> (); @NonEmpty Collection <@NonEmpty String> strings = new ArrayList <> (); -ElementType.type_user และ ElementType.type_Parameter เป็นคำอธิบายประกอบใหม่สองรายการที่เพิ่มเข้ามาใน Java 8 เพื่ออธิบายสถานการณ์การใช้งานของคำอธิบายประกอบ ภาษาชวา
หยานยังทำการเปลี่ยนแปลงที่สอดคล้องกันเพื่อระบุบันทึกที่เพิ่มขึ้นใหม่เหล่านี้
3. คุณสมบัติใหม่ของคอมไพเลอร์ Java
3.1 ชื่อพารามิเตอร์
เพื่อให้ได้ชื่อพารามิเตอร์ของวิธีการในโปรแกรม Java ที่รันไทม์โปรแกรมเมอร์ Java รุ่นเก่าจะต้องใช้วิธีการที่แตกต่างกันเช่น Paranamer Imalary Java 8 ในที่สุดก็ทำให้คุณลักษณะนี้เป็นปกติโดยมีการสนับสนุนในระดับภาษา (ใช้วิธีการสะท้อน API และพารามิเตอร์. getName ()) และระดับ bytecode (ใช้คอมไพเลอร์ Javac ใหม่และพารามิเตอร์ -parameters)
แพ็คเกจ com.javacodegeeks.java8.parameter.names; นำเข้า java.lang.reflect.method; นำเข้า java.lang.reflect.parameter; พารามิเตอร์คลาสสาธารณะ {โมฆะคงที่สาธารณะหลัก (สตริง [] args) พ่นข้อยกเว้น {วิธีการ = parameterNames.class.getMethod ("หลัก", สตริง []. คลาส); สำหรับ (พารามิเตอร์พารามิเตอร์สุดท้าย: method.getParameters ()) {system.out.println ("พารามิเตอร์:" + parameter.getName ());}}}ใน Java 8 คุณสมบัตินี้จะถูกปิดโดยค่าเริ่มต้นดังนั้นหากคุณรวบรวมรหัสด้านบนโดยไม่มีพารามิเตอร์ -parameters และเรียกใช้ผลลัพธ์ต่อไปนี้จะถูกส่งออก:
พารามิเตอร์: Arg0
หากใช้พารามิเตอร์ -parameters ผลลัพธ์ต่อไปนี้จะเป็นเอาต์พุต (ผลลัพธ์ที่ถูกต้อง):
พารามิเตอร์: args
หากคุณใช้ Maven สำหรับการจัดการโครงการคุณสามารถกำหนดค่าพารามิเตอร์ -parameters ในรายการการกำหนดค่าคอมไพเลอร์ Maven-Compiler-Plugin
<plugin> <sloupid> org.apache.maven.plugins </groupId> <ratifactid> maven-compiler-plugin </artifactid> <sersion> 3.1 </version> <การกำหนดค่า> <CompilerArgument> -parameters </Compilerarument>
4. คุณสมบัติใหม่ของห้องสมุดอย่างเป็นทางการของ Java
Java 8 ได้เพิ่มคลาสเครื่องมือใหม่จำนวนมาก (คลาสวันที่/เวลา) และขยายคลาสเครื่องมือที่มีอยู่เพื่อรองรับการเขียนโปรแกรมพร้อมกันที่ทันสมัยการเขียนโปรแกรมการทำงาน ฯลฯ
4.1 เป็นทางเลือก
ข้อผิดพลาดที่พบบ่อยที่สุดในแอปพลิเคชัน Java คือข้อยกเว้นค่า NULL ก่อน Java 8 Google Guava แนะนำคลาส Optionals เพื่อแก้ปัญหา Nullpointerexception ดังนั้นจึงหลีกเลี่ยงซอร์สโค้ดที่ถูกปนเปื้อนโดยการตรวจสอบ null ต่างๆเพื่อให้นักพัฒนาสามารถเขียนรหัสทำความสะอาดได้ Java 8 ยังเพิ่มตัวเลือกให้กับห้องสมุดอย่างเป็นทางการ
ตัวเลือกเป็นเพียงสิ่งที่ง่าย: เก็บค่าประเภท t หรือ null มันมีอินเทอร์เฟซที่มีประโยชน์บางอย่างเพื่อหลีกเลี่ยงการตรวจสอบโมฆะอย่างชัดเจนและคุณสามารถอ้างถึงเอกสาร Java 8 อย่างเป็นทางการสำหรับรายละเอียดเพิ่มเติม
จากนั้นลองมาดูตัวอย่างการใช้ตัวเลือก: ค่าที่อาจว่างเปล่าหรือค่าหนึ่งประเภท:
ตัวเลือก <String> fullName = potainal.ofnullable (null); system.out.println ("ตั้งชื่อเต็ม?" + fullName.ispresent ()); System.out.println ("ชื่อเต็ม:" + fullname.orelseget (() -> "[ไม่มี]")); System.out.println (fullName.map (s -> "เฮ้" + s + "!") .orelse ("เฮ้คนแปลกหน้า!"));หากอินสแตนซ์ที่เป็นตัวเลือกมีค่าที่ไม่ใช่ NULL เมธอด ispresent () จะส่งคืนจริงมิฉะนั้นจะส่งคืนเท็จ เมธอด orelseget () และอินสแตนซ์ที่เป็นตัวเลือกถือเป็นโมฆะสามารถยอมรับค่าเริ่มต้นที่สร้างขึ้นโดยนิพจน์แลมบ์ดา เมธอดแผนที่ () สามารถแปลงค่าของอินสแตนซ์ตัวเลือกที่มีอยู่เป็นค่าใหม่ วิธี orelse () คล้ายกับวิธี orelseget () แต่ส่งคืนค่าเริ่มต้นที่ผ่านเมื่อถือ null
ผลลัพธ์ผลลัพธ์ของรหัสข้างต้นมีดังนี้:
ตั้งชื่อเต็มแล้ว? ชื่อเต็มเท็จ: [ไม่มี] เฮ้คนแปลกหน้า!
ลองมาดูตัวอย่างง่ายๆอีกตัวอย่างหนึ่ง:
ตัวเลือก <String> FIRSTNAME = POVILAL.OF ("TOM"); System.out.println ("ตั้งชื่อแรก?" + firstName.ispresent ()); System.out.println ("ชื่อแรก:" + firstName.orelseget (() -> "[ไม่มี]")); System.out.println (firstName.map (s -> "เฮ้" + s + "!") .orelse ("เฮ้คนแปลกหน้า!")); System.out.println ();ผลลัพธ์ของตัวอย่างนี้คือ:
ตั้งชื่อแรกแล้ว? ชื่อจริงชื่อ: ทอมเฮ้ทอม!
หากคุณต้องการทราบรายละเอียดเพิ่มเติมโปรดดูเอกสารอย่างเป็นทางการ
4.2 สตรีม
API สตรีมที่เพิ่มขึ้นใหม่ (java.util.stream) แนะนำการเขียนโปรแกรมการทำงานของสภาพแวดล้อมที่สร้างขึ้นในไลบรารี Java นี่คือการปรับปรุงห้องสมุด Java ที่ใหญ่ที่สุดเพื่อให้นักพัฒนาสามารถเขียนโค้ดที่มีประสิทธิภาพกระชับและกะทัดรัดมากขึ้น
Steam API ช่วยลดความซับซ้อนของการดำเนินการคอลเลกชันได้อย่างมาก (เราจะเห็นมากกว่าแค่คอลเลกชันในภายหลัง) ก่อนอื่นมาดูคลาสนี้ที่เรียกว่างาน:
สตรีมคลาสสาธารณะ {สถานะ enum ส่วนตัว {เปิดปิด}; งานคลาสสุดท้ายแบบคงที่ส่วนตัว {สถานะสถานะสุดท้ายส่วนตัว; คะแนนจำนวนเต็มสุดท้ายส่วนตัว; งาน (สถานะสถานะสุดท้าย, คะแนนจำนวนเต็มสุดท้าย) {this.status = สถานะ; this.points = points;} public integer getPoints () {คะแนนคืน;} สถานะสาธารณะ getStatus () {สถานะการส่งคืน;} @Override สตริงสาธารณะ toString () {return string.format ("[ %s, %d]", สถานะ, คะแนน);}}}}}}}}}}}}}คลาสงานมีแนวคิดเรื่องเศษส่วน (หรือความซับซ้อนแบบหลอก) และมีอีกสองสถานะ: เปิดหรือปิด ตอนนี้สมมติว่ามีการรวบรวมงาน:
คอลเลกชันสุดท้าย <Sask> tasks = arrays.aslist (งานใหม่ (status.open, 5), งานใหม่ (status.open, 13), งานใหม่ (status.closed, 8));
ก่อนอื่นมาดูคำถาม: มีจุดเปิดมีกี่จุดในคอลเลกชันงานนี้? ก่อน Java 8 เพื่อแก้ปัญหานี้คุณต้องใช้ foreach เพื่อวนรอบการรวบรวมงาน อย่างไรก็ตามใน Java 8 คุณสามารถใช้ Steams เพื่อแก้ปัญหา: รวมรายการของชุดองค์ประกอบและสนับสนุนการประมวลผลตามลำดับและการประมวลผลแบบขนาน
// คำนวณจุดรวมของงานที่ใช้งานทั้งหมดโดยใช้ผลรวม () Final TotalPointSofOpentAsks = tasks.stream (). ตัวกรอง (task -> task.getStatus () == status.Open) .Maptoint (Task :: getPoints) .sum ();
เอาต์พุตคอนโซลสำหรับการเรียกใช้วิธีนี้คือ:
คะแนนรวม: 18
มีหลายจุดความรู้ที่ควรค่าแก่การพูดคุยเกี่ยวกับที่นี่ ขั้นแรกชุดงานจะถูกแปลงเป็นตัวแทนไอน้ำ ประการที่สองการดำเนินการกรองบนตัวกรองไอน้ำออกจากงานที่ปิดทั้งหมด ประการที่สามการดำเนินการ maptoint แปลงสตรีมงานเป็นคอลเลกชันจำนวนเต็มตามวิธีการ :: getPoints ของแต่ละอินสแตนซ์งาน; ในที่สุดผลรวมจะถูกคำนวณโดยวิธี SUM เพื่อให้ได้ผลลัพธ์สุดท้าย
ก่อนที่จะเรียนรู้ตัวอย่างต่อไปคุณต้องจดจำคะแนนความรู้บางอย่างเกี่ยวกับ Steams (คลิกที่นี่เพื่อดูรายละเอียดเพิ่มเติม) การดำเนินงานข้างต้น Steam สามารถแบ่งออกเป็นการดำเนินงานระดับกลางและการดำเนินการล่าช้า
การดำเนินการระดับกลางจะส่งคืนไอน้ำใหม่ - การดำเนินการระดับกลาง (เช่นตัวกรอง) จะไม่ดำเนินการกรองจริง แต่สร้างไอน้ำใหม่และวางองค์ประกอบที่ตรงกับเงื่อนไขในไอน้ำดั้งเดิมลงในไอน้ำที่สร้างขึ้นใหม่
การดำเนินการล่าช้า (เช่น foreach หรือผลรวม) จะสำรวจไอน้ำและรับผลลัพธ์หรือผลลัพธ์ที่มาจาก; หลังจากดำเนินการล่าช้าสายการประมวลผลไอน้ำได้รับการประมวลผลและไม่สามารถใช้งานได้ ในเกือบทุกกรณีการดำเนินการล่าช้าจะผ่านไอน้ำทันที
อีกหนึ่งค่าของ Steam คือการสนับสนุนที่สร้างสรรค์สำหรับการประมวลผลแบบขนาน สำหรับการรวบรวมงานข้างต้นเราสามารถใช้รหัสต่อไปนี้เพื่อคำนวณผลรวมของจุดทั้งหมด:
// คำนวณจุดรวมของงานทั้งหมดสองจุดรวมจุดรวม = tasks.stream (). ขนาน (). แผนที่ (งาน -> task.points ()) // หรือแผนที่ (งาน :: getpoints). ลด (0, จำนวนเต็ม :: sum);
ที่นี่เราใช้วิธีการขนานเพื่อประมวลผลงานทั้งหมดแบบขนานและคำนวณผลลัพธ์สุดท้ายโดยใช้วิธีการลด เอาต์พุตคอนโซลมีดังนี้:
คะแนนรวม (งานทั้งหมด): 26.0
สำหรับการรวบรวมมักจะจำเป็นต้องจัดกลุ่มองค์ประกอบในนั้นตามเงื่อนไขบางประการ งานประเภทนี้สามารถเสร็จสิ้นได้อย่างรวดเร็วโดยใช้ API ที่จัดทำโดย Steam รหัสมีดังนี้:
// งานกลุ่มตามสถานะสถานะสุดท้าย <สถานะ, รายการ <task>> map = tasks.stream (). collect (collectors.groupingby (งาน :: getStatus)); System.out.println (แผนที่);
ผลลัพธ์ของคอนโซลมีดังนี้:
{ปิด = [[ปิด, 8]], open = [[เปิด, 5], [เปิด, 13]]}
ตัวอย่างคำถามสุดท้ายเกี่ยวกับการรวบรวมงานคือ: วิธีการคำนวณสัดส่วนของจุดของแต่ละงานในคอลเลกชันในคอลเลกชัน รหัสการประมวลผลเฉพาะมีดังนี้:
// คำนวณน้ำหนักของแต่ละงาน (เป็นเปอร์เซ็นต์ของคะแนนรวม) คอลเลกชันสุดท้าย <string> result = tasks.stream () // สตรีม <String> .Maptoint (งาน :: getPoints) // intstream .aslongstream () // longstream. )) // longstream .MaptOOBJ (เปอร์เซ็นต์ -> เปอร์เซ็นต์ + "%") // สตรีม <String> .Collect (collector.tolist ()); // รายการ <String> System.out.println (ผลลัพธ์);
ผลลัพธ์ของเอาต์พุตคอนโซลมีดังนี้:
[19%, 50%, 30%]
ในที่สุดดังที่ได้กล่าวไว้ก่อนหน้านี้ Steam API ไม่เพียง แต่สามารถดำเนินการในคอลเลกชัน Java แต่การดำเนินการ IO แบบดั้งเดิม (อ่านข้อมูลจากไฟล์หรือบรรทัดเครือข่ายทีละบรรทัด) สามารถได้รับประโยชน์จากการประมวลผล Steam นี่คือตัวอย่างเล็ก ๆ :
PATH FINAL PATH = ไฟล์ใหม่ (ชื่อไฟล์) .topath (); ลอง (สตรีม <String> lines = files.lines (path, StandardCharSets.UTF_8)) {lines.onclose (() -> system.out.println ("เสร็จสิ้น!")). foreach (system.out :: println);};วิธีการสตรีม onclose ส่งคืนสตรีมที่เทียบเท่าพร้อมที่จับเพิ่มเติม มือจับนี้จะถูกดำเนินการเมื่อเรียกใช้วิธีการปิด () ของสตรีม สตรีม API, Lambda Expressions และวิธีการอ้างอิงที่ได้รับการสนับสนุนโดยวิธีการเริ่มต้นอินเตอร์เฟสและวิธีการคงที่คือการตอบสนองของ Java 8 ต่อกระบวนทัศน์ที่ทันสมัยของการพัฒนาซอฟต์แวร์
4.3 วันที่/เวลา API (JSR 310)
Java 8 แนะนำ API เวลาวันที่ใหม่ (JSR 310) เพื่อปรับปรุงการประมวลผลเวลาและวันที่ การจัดการเวลาและวันที่เป็นปัญหาที่เจ็บปวดที่สุดสำหรับนักพัฒนา Java java.util.date และต่อมา java.util.calendar ไม่ได้แก้ไขปัญหานี้ (ผู้พัฒนาสับสนมากยิ่งขึ้น)
ด้วยเหตุผลข้างต้น Joda-Time ห้องสมุดบุคคลที่สามเกิดซึ่งสามารถแทนที่ API การจัดการเวลาของ Java API การจัดการเวลาและวันที่ใหม่ใน Java 8 ได้รับอิทธิพลอย่างลึกซึ้งจาก Joda-Time และได้ดูดซับสาระสำคัญของ Joda-Time มากมาย แพ็คเกจ Java.time ใหม่มีคลาสทั้งหมดเกี่ยวกับวันที่เวลาเวลาเขตเวลาทันที (คล้ายกับวันที่ แต่แม่นยำถึงนาโนวินาที) ระยะเวลา (ระยะเวลา) และการดำเนินการนาฬิกา API ที่ได้รับการออกแบบใหม่จะพิจารณาถึงความไม่เปลี่ยนแปลงของชั้นเรียนเหล่านี้ (การบรรยายที่เรียนรู้จาก java.util.calendar) และส่งคืนวัตถุใหม่หากจำเป็นต้องแก้ไขอินสแตนซ์
ลองมาดูคลาสสำคัญและตัวอย่างการใช้งานตามลำดับในแพ็คเกจ Java.time ขั้นแรกคลาสนาฬิกาใช้โซนเวลาเพื่อส่งคืนเวลาและวันที่นาโนปัจจุบัน นาฬิกาสามารถแทนที่ System.currentTimeMillis () และ Timezone.getDefault ()
// รับนาฬิการะบบเป็น UTC OFFSET นาฬิกานาฬิกาสุดท้าย = นาฬิกา SYSTEMUTC (); System.out.println (clock.instant ()); system.out.println (clock.millis ());
ผลลัพธ์ของตัวอย่างนี้คือ:
2014-04-12T15: 19: 29.282Z 1397315969360
ประการที่สองมุ่งเน้นไปที่คลาส LocalDate และ LocalTime LocalDate มีเพียงส่วนวันที่ในระบบปฏิทิน ISO-8601 เท่านั้น LocalTime มีเพียงส่วนเวลาในระบบปฏิทิน วัตถุของทั้งสองคลาสสามารถสร้างได้โดยใช้วัตถุนาฬิกา
// รับวันที่ท้องถิ่นและเวลาท้องถิ่นวันที่ localDate สุดท้าย = localDate.now (); สุดท้าย localDate วันที่วันที่ FromClock = localDate.now (นาฬิกา); System.out.println (DateFromClock); // รับวันที่ท้องถิ่นและเวลาท้องถิ่นเวลา localtime สุดท้าย = localtime.now (); สุดท้าย LocalTime TimeFromClock = localTime.now (นาฬิกา); System.out.println (เวลา); System.out.println (TimeFromClock);
ผลลัพธ์ผลลัพธ์ของตัวอย่างข้างต้นมีดังนี้:
2014-04-12 2014-04-12 11: 25: 54.568 15: 25: 54.568
คลาส LocalDateTime มีข้อมูลเกี่ยวกับ LocalDate และ LocalTime แต่ไม่มีข้อมูลโซนเวลาในระบบปฏิทิน ISO-8601 นี่คือตัวอย่างบางส่วนเกี่ยวกับ LocalDate และ LocalTime:
// รับวันที่/เวลาท้องถิ่นสุดท้าย localDateTime dateTime = localDateTime.now (); localDateTime สุดท้าย dateTimeFromClock = localDatetime.now (นาฬิกา); System.out.println (DateTime); System.out.println (DateTimeFromClock);
ผลลัพธ์ผลลัพธ์ของตัวอย่างข้างต้นมีดังนี้:
2014-04-12T11: 37: 52.309 2014-04-12T15: 37: 52.309
หากคุณต้องการข้อมูลข้อมูล/เวลาสำหรับโซนเวลาที่เฉพาะเจาะจงคุณสามารถใช้ ZonEdateTime ซึ่งถือวันที่และเวลาของระบบวันที่ ISO-8601 และมีข้อมูลโซนเวลา นี่คือตัวอย่างของการใช้โซนเวลาที่แตกต่างกัน:
// รับ Zoned Date/Time Final ZonedDateTime ZonedDateTime = ZonedDatetime.now (); Final ZonedDateTime ZonedDateTimeFromClock = ZonEdDateTime.now (นาฬิกา); Final ZonedDateTime ZonedDateTimeFromzone = ZonedDateTime.now (ZoneID.OF ("America/LOS_ANGELES")); System.out.println (ZonedDateTime); System.out.println (ZonedDateTimeFromClock); System.out.println (ZonedDateTimeFromClock); System.out.println (ZonedDateTimeFromzone);ผลลัพธ์ของตัวอย่างนี้คือ:
2014-04-12T11: 47: 01.017-04: 00 [America/New_york] 2014-04-12T15: 47: 01.017Z 2014-04-12T08: 47: 01.017-07: 00 [America/Los_Angeles]
สุดท้ายมาดูคลาสระยะเวลาซึ่งมีเวลาเป็นวินาทีและนาโนวินาที สิ่งนี้ทำให้ง่ายต่อการคำนวณความแตกต่างระหว่างสองวันที่รหัสตัวอย่างมีดังนี้:
// ได้รับระยะเวลาระหว่างสองวันสุดท้าย localDateTime จาก = localDateTime.of (2014, เดือนเมษายน, 16, 0, 0, 0); localDateTime สุดท้ายถึง = localDateTime.of (2015, เดือนเมษายน, 16, 23, 59, 59); duration.todays ()); System.out.println ("ระยะเวลาเป็นชั่วโมง:" + duration.tohours ());ตัวอย่างนี้ใช้ในการคำนวณจำนวนวันและชั่วโมงระหว่างวันที่ 16 เมษายน 2014 ถึง 16 เมษายน 2558 และผลลัพธ์มีดังนี้:
ระยะเวลาในวัน: 365 ระยะเวลาในชั่วโมง: 8783
ความประทับใจโดยรวมของวันและเวลาใหม่ของ Java 8 นั้นค่อนข้างเป็นบวกส่วนหนึ่งเป็นเพราะผลกระทบเชิงบวกของโจดา-เวลาและส่วนหนึ่งเป็นเพราะเจ้าหน้าที่ในที่สุดก็ฟังความต้องการของนักพัฒนา หากคุณต้องการทราบรายละเอียดเพิ่มเติมคุณสามารถอ้างอิงเอกสารอย่างเป็นทางการ
4.4 เครื่องยนต์ Nashorn JavaScript
Java 8 ให้บริการเครื่องยนต์ Nashorn JavaScript ใหม่ช่วยให้เราสามารถพัฒนาและเรียกใช้แอปพลิเคชัน JS บน JVM Nashorn JavaScript Engine เป็นอีกเวอร์ชันการใช้งานของ javax.script.scriptEngine เอ็นจิ้นสคริปต์ประเภทนี้เป็นไปตามกฎเดียวกันและอนุญาตให้ใช้ Java และ JavaScript แบบโต้ตอบ รหัสตัวอย่างมีดังนี้:
ScriptenginManager Manager = ใหม่ ScriptenginAnager (); ScriptEngine Engine = manager.getEngineByName ("JavaScript"); System.out.println (engine.getClass (). getName ()); system.out.println ("ผลลัพธ์:" + engine.eval ("ฟังก์ชั่น f ()ผลลัพธ์ของรหัสนี้มีดังนี้:
jdk.nashorn.api.scripting.nashornscriptEngine ผลลัพธ์: 2
4.5 base64
การสนับสนุนสำหรับการเข้ารหัส Base64 ได้ถูกเพิ่มเข้าไปในห้องสมุด Java 8 อย่างเป็นทางการดังนั้นการเข้ารหัส Base64 สามารถทำได้โดยไม่ต้องใช้ห้องสมุดบุคคลที่สาม รหัสตัวอย่างมีดังนี้:
แพ็คเกจ com.javacodegeeks.java8.base64; นำเข้า java.nio.charset.standardcharsets; นำเข้า java.util.base64; คลาสสาธารณะ base64s {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {ข้อความสตริงสุดท้าย = "base64 ในที่สุดใน Java 8!"; สตริงสุดท้าย encoded = base64.getEncoder (). encodetoString (text.getBytes (StandardCharSets.UTF_8)); System.out.println (เข้ารหัส); การถอดรหัสสตริงสุดท้าย = สตริงใหม่ (base64.getDecoder (). decode (เข้ารหัส), StandardCharSets.UTF_8); System.out.println (ถอดรหัส);}}ผลลัพธ์ของตัวอย่างนี้มีดังนี้:
QMFZZTY0IGZPBMFSBHKGAW4GSMF2YSA4IQ ==
Base64 ในที่สุดใน Java 8!
Base64API ใหม่ยังรองรับการเข้ารหัสและถอดรหัส URL และเหมือง
(base64.geturlencoder () / base64.geturldecoder (), base64.getMimeEncoder () / base64.getMimimedecoder ())
4.6 อาร์เรย์ขนาน
เวอร์ชัน Java8 ได้เพิ่มวิธีการใหม่ ๆ มากมายเพื่อรองรับการประมวลผลอาร์เรย์แบบขนาน วิธีที่สำคัญที่สุดคือ Parallelesort () ซึ่งสามารถเพิ่มความเร็วในการเรียงลำดับอาร์เรย์บนเครื่องหลายคอร์ ตัวอย่างต่อไปนี้แสดงวิธีการของชุด parallexxxxx:
แพ็คเกจ com.javacodegeeks.java8.parallel.arrays; นำเข้า java.util.arrays; นำเข้า java.util.concurrent.threadlocalrandom; Public Class ParallelArrays {โมฆะสาธารณะคงที่หลัก (String [] args) {long [] arrayoflong = ใหม่ยาว [20000]; Arrays.parallelSetAll( arrayOfLong, index -> ThreadLocalRandom.current().nextInt( 1000000 ) );Arrays.stream( arrayOfLong ).limit( 10 ).forEach( i -> System.out.print( i + " " ) );System.out.println();Arrays.parallelSort( arrayOfLong );Arrays.stream( arrayOfLong ).limit( 10 ).forEach( i -> System.out.print( i + " " ) );System.out.println();}}上述这些代码使用parallelSetAll()方法生成20000个随机数,然后使用parallelSort()方法进行排序。这个程序会输出乱序数组和排序数组的前10个元素。上述例子的代码输出的结果是:
Unsorted: 591217 891976 443951 424479 766825 351964 242997 642839 119108 552378 Sorted: 39 220 263 268 325 607 655 678 723 793
4.7 并发性
基于新增的lambda表达式和steam特性,为Java 8中为java.util.concurrent.ConcurrentHashMap类添加了新的方法来支持聚焦操作;另外,也为java.util.concurrentForkJoinPool类添加了新的方法来支持通用线程池操作(更多内容可以参考我们的并发编程课程)。
Java 8还添加了新的java.util.concurrent.locks.StampedLock类,用于支持基于容量的锁――该锁有三个模型用于支持读写操作(可以把这个锁当做是java.util.concurrent.locks.ReadWriteLock的替代者)。
在java.util.concurrent.atomic包中也新增了不少工具类,列举如下:
DoubleAccumulator
DoubleAdder
LongAccumulator
LongAdder
5. 新的Java工具
Java 8提供了一些新的命令行工具,这部分会讲解一些对开发者最有用的工具。
5.1 Nashorn引擎:jjs
jjs是一个基于标准Nashorn引擎的命令行工具,可以接受js源码并执行。例如,我们写一个func.js文件,内容如下:
function f() { return 1; - print( f() + 1 );可以在命令行中执行这个命令:jjs func.js,控制台输出结果是:
2
如果需要了解细节,可以参考官方文档。
5.2 类依赖分析器:jdeps
jdeps是一个相当棒的命令行工具,它可以展示包层级和类层级的Java类依赖关系,它以.class文件、目录或者Jar文件为输入,然后会把依赖关系输出到控制台。
我们可以利用jedps分析下Spring Framework库,为了让结果少一点,仅仅分析一个JAR文件:org.springframework.core-3.0.5.RELEASE.jar。
jdeps org.springframework.core-3.0.5.RELEASE.jar
这个命令会输出很多结果,我们仅看下其中的一部分:依赖关系按照包分组,如果在classpath上找不到依赖,则显示”not found”.
org.springframework.core-3.0.5.RELEASE.jar -> C:/Program Files/Java/jdk1.8.0/jre/lib/rt.jarorg.springframework.core (org.springframework.core-3.0.5.RELEASE.jar)-> java.io -> java.lang -> java.lang.annotation -> java.lang.ref -> java.lang.reflect -> java.util -> java.util.concurrent -> org.apache.commons.logging not found-> org.springframework.asm not found-> org.springframework.asm.commons not foundorg.springframework.core.annotation (org.springframework.core-3.0.5.RELEASE.jar)-> java.lang -> java.lang.annotation -> java.lang.reflect -> java.util
更多的细节可以参考官方文档。
6. JVM的新特性
使用Metaspace(JEP 122)代替持久代(PermGen space)。在JVM参数方面,使用-XX:MetaSpaceSize和-XX:MaxMetaspaceSize代替原来的-XX:PermSize和-XX:MaxPermSize。
7. 结论
通过为开发者提供很多能够提高生产力的特性,Java 8使得Java平台前进了一大步。现在还不太适合将Java 8应用在生产系统中,但是在之后的几个月中Java 8的应用率一定会逐步提高(PS:原文时间是2014年5月9日,现在在很多公司Java 8已经成为主流,我司由于体量太大,现在也在一点点上Java 8,虽然慢但是好歹在升级了)。作为开发者,现在应该学习一些Java 8的知识,为升级做好准备。