JavaRush /จาวาบล็อก /Random-TH /คู่มือจาวา 8 1 ส่วน.
ramhead
ระดับ

คู่มือจาวา 8 1 ส่วน.

เผยแพร่ในกลุ่ม

“ชวายังมีชีวิตอยู่ และผู้คนก็เริ่มเข้าใจมันแล้ว”

ยินดีต้อนรับสู่การแนะนำ Java 8 ของฉัน คู่มือนี้จะแนะนำคุณทีละขั้นตอนผ่านคุณสมบัติใหม่ทั้งหมดของภาษา จากตัวอย่างโค้ดสั้นๆ ง่ายๆ คุณจะ ได้ เรียน รู้วิธีใช้วิธีการเริ่มต้นของอินเทอร์เฟซ นิพจน์ lambda วิธีการอ้างอิงและคำอธิบายประกอบที่ทำซ้ำได้ ในตอนท้ายของบทความ คุณจะคุ้นเคยกับการเปลี่ยนแปลงล่าสุดใน API เช่น สตรีม อินเทอร์เฟซฟังก์ชัน ส่วนขยายการเชื่อมโยง และ Date API ใหม่ ไม่มีกำแพงข้อความที่น่าเบื่อ - เป็นเพียงตัวอย่างโค้ดแสดงความคิดเห็นจำนวนมาก สนุก!

วิธีการเริ่มต้นสำหรับอินเทอร์เฟซ

Java 8 อนุญาตให้เราเพิ่มวิธีการที่ไม่ใช่นามธรรมที่นำมาใช้ในอินเทอร์เฟซผ่าน การ ใช้ คำหลัก เริ่มต้น คุณลักษณะนี้เรียกอีกอย่างว่าวิธี การขยาย นี่คือตัวอย่างแรกของเรา: interface Formula { double calculate(int a); default double sqrt(int a) { return Math.sqrt(a); } } นอกเหนือจากวิธี abstract คำนวณ แล้วอิน เทอร์เฟซ Formulaยังกำหนดวิธีการเริ่มต้น sqrt อีก ด้วย คลาสที่ใช้ อินเทอร์ เฟซสูตรจะใช้เฉพาะ วิธี การคำนวณ เชิงนามธรรม เท่านั้น คุณสามารถใช้วิธี sqrtเริ่มต้นได้ทันทีที่แกะกล่อง Formula formula = new Formula() { @Override public double calculate(int a) { return sqrt(a * 100); } }; formula.calculate(100); // 100.0 formula.sqrt(16); // 4.0 ออบเจ็กต์ สูตรถูกนำมาใช้เป็นออบเจ็กต์ที่ไม่ระบุชื่อ รหัสนี้ค่อนข้างน่าประทับใจ: โค้ด 6 บรรทัดเพื่อคำนวณ sqrt(a * 100 ) ดังที่เราจะเห็นในหัวข้อถัดไป มีวิธีที่น่าสนใจมากขึ้นในการใช้อ็อบเจ็กต์วิธีเดียวใน Java 8

นิพจน์แลมบ์ดา

เรามาเริ่มด้วยตัวอย่างง่ายๆ ของวิธีการเรียงลำดับอาร์เรย์ของสตริงใน Java เวอร์ชันแรกๆ: เมธอดตัวช่วยทางสถิติ Collections.sortรับรายการและตัวเปรียบเทียบ เพื่อเรียงลำดับองค์ประกอบของรายการที่กำหนด สิ่งที่มักเกิดขึ้นคือคุณสร้างตัวเปรียบเทียบที่ไม่ระบุชื่อและส่งต่อไปยังวิธีการเรียงลำดับ แทนที่จะสร้างอ็อบเจ็กต์ที่ไม่ระบุชื่อตลอดเวลา Java 8 ให้ความสามารถในการใช้ไวยากรณ์นิพจน์แลมบ์ดาน้อยลงมากอย่าง ที่ คุณเห็นโค้ดนั้นสั้นกว่ามากและอ่านง่ายกว่ามาก แต่ที่นี่จะสั้นลงอีก: สำหรับวิธีบรรทัดเดียว คุณสามารถกำจัด เครื่องหมายปีกกา {} และ คีย์เวิร์ด returnได้ แต่นี่คือจุดที่โค้ดจะสั้นลง: คอมไพลเลอร์ Java รับรู้ถึงประเภทของพารามิเตอร์ ดังนั้นคุณจึงสามารถละเว้นพารามิเตอร์เหล่านั้นได้เช่นกัน ทีนี้มาเจาะลึกลงไปว่านิพจน์แลมบ์ดาสามารถนำมาใช้ในชีวิตจริงได้อย่างไร List names = Arrays.asList("peter", "anna", "mike", "xenia"); Collections.sort(names, new Comparator () { @Override public int compare(String a, String b) { return b.compareTo(a); } }); Collections.sort(names, (String a, String b) -> { return b.compareTo(a); }); Collections.sort(names, (String a, String b) -> b.compareTo(a)); Collections.sort(names, (a, b) -> b.compareTo(a));

อินเตอร์เฟซการทำงาน

นิพจน์แลมบ์ดาเหมาะสมกับระบบประเภท Java อย่างไร แลมบ์ดาแต่ละตัวสอดคล้องกับประเภทที่กำหนดโดยอินเทอร์เฟซ และส่วนต่อประสานการทำงานที่เรียกว่าจะต้องมีวิธีนามธรรมที่ประกาศไว้เพียงวิธีเดียวเท่านั้น lambda expression ทุกนิพจน์ของประเภทที่กำหนดจะสอดคล้องกับวิธี abstract นี้ เนื่องจากวิธีการเริ่มต้นไม่ใช่วิธี abstract คุณจึงมีอิสระที่จะเพิ่มวิธีการเริ่มต้นลงในอินเทอร์เฟซการทำงานของคุณ เราสามารถใช้อินเทอร์เฟซที่กำหนดเองเป็นนิพจน์แลมบ์ดาได้ โดยมีเงื่อนไขว่าอินเทอร์เฟซจะมีวิธีนามธรรมเพียงวิธีเดียวเท่านั้น เพื่อให้แน่ใจว่าอินเทอร์เฟซของคุณตรงตามเงื่อนไขเหล่า นี้คุณต้องเพิ่ม คำอธิบายประกอบ @FunctionalInterface คอมไพเลอร์จะได้รับแจ้งจากคำอธิบายประกอบนี้ว่าอินเทอร์เฟซต้องมีเพียงวิธีเดียวเท่านั้น และหากพบวิธีนามธรรมที่สองในอินเทอร์เฟซนี้ ก็จะเกิดข้อผิดพลาด ตัวอย่าง: โปรดทราบว่าโค้ดนี้จะใช้ได้แม้ว่าจะไม่ได้ประกาศ คำอธิบายประกอบ @FunctionalInterface ก็ตาม @FunctionalInterface interface Converter { T convert(F from); } Converter converter = (from) -> Integer.valueOf(from); Integer converted = converter.convert("123"); System.out.println(converted); // 123

การอ้างอิงถึงวิธีการและตัวสร้าง

ตัวอย่างข้างต้นสามารถทำให้ง่ายขึ้นได้โดยใช้การอ้างอิงวิธีการทางสถิติ: Java 8 ช่วยให้คุณสามารถส่งผ่านการอ้างอิงไปยังวิธีการและตัวสร้างโดยใช้ สัญลักษณ์ คำ หลัก :: ตัวอย่างข้างต้นแสดงวิธีการใช้วิธีการทางสถิติ แต่เรายังสามารถอ้างอิงวิธีการบนอ็อบเจ็กต์ได้: มาดูกันว่าการใช้ ::ทำงานอย่างไรกับคอนสตรัคเตอร์ ขั้นแรก เรามากำหนดตัวอย่างด้วยตัวสร้างที่แตกต่างกัน: ต่อไป เราจะกำหนด อินเทอร์เฟซโรงงาน PersonFactoryสำหรับการสร้าง อ็อบเจ็กต์ บุคคล ใหม่ : Converter converter = Integer::valueOf; Integer converted = converter.convert("123"); System.out.println(converted); // 123 class Something { String startsWith(String s) { return String.valueOf(s.charAt(0)); } } Something something = new Something(); Converter converter = something::startsWith; String converted = converter.convert("Java"); System.out.println(converted); // "J" class Person { String firstName; String lastName; Person() {} Person(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } } interface PersonFactory

{ P create(String firstName, String lastName); } แทนที่จะดำเนินการโรงงานด้วยตนเอง เราเชื่อมโยงทุกอย่างเข้าด้วยกันโดยใช้การอ้างอิงคอนสตรัคเตอร์: เราสร้างการอ้างอิงถึงคอนสตรัคเตอร์ของ คลาส Personผ่านPerson:: new คอมไพลเลอร์ Java จะเรียกตัวสร้างที่เหมาะสมโดย อัตโนมัติ โดยการเปรียบเทียบลายเซ็นของตัวสร้างกับลายเซ็นของ เมธอด PersonFactory.createPersonFactory personFactory = Person::new; Person person = personFactory.create("Peter", "Parker");

ภูมิภาคแลมบ์ดา

การจัดระเบียบการเข้าถึงตัวแปรขอบเขตภายนอกจากนิพจน์แลมบ์ดานั้นคล้ายคลึงกับการเข้าถึงจากออบเจ็กต์ที่ไม่ระบุชื่อ คุณสามารถเข้าถึง ตัวแปร สุดท้ายได้จากขอบเขตภายในเครื่อง รวมถึงช่องอินสแตนซ์และตัวแปรรวม
การเข้าถึงตัวแปรท้องถิ่น
เราสามารถอ่านตัวแปรภายในเครื่องด้วย ตัวแก้ไข สุดท้ายจากขอบเขตของนิพจน์แลมบ์ดา: แต่ตัวแปรต่างจากวัตถุที่ไม่ระบุชื่อตรงที่ตัวแปรไม่จำเป็นต้องได้รับการประกาศ ขั้นสุดท้าย เพื่อให้สามารถเข้าถึงได้จากนิพจน์แลมบ์ ดา รหัสนี้ถูกต้องเช่นกัน: อย่างไรก็ตาม ตัวแปร numจะต้องไม่เปลี่ยนรูป เช่น ถือเป็น ที่สิ้นสุด โดยนัย สำหรับการรวบรวมโค้ด รหัสต่อไปนี้จะไม่คอมไพล์: ไม่อนุญาต ให้ เปลี่ยนแปลง num ภายในนิพจน์แลมบ์ดาเช่นกัน final int num = 1; Converter stringConverter = (from) -> String.valueOf(from + num); stringConverter.convert(2); // 3 int num = 1; Converter stringConverter = (from) -> String.valueOf(from + num); stringConverter.convert(2); // 3 int num = 1; Converter stringConverter = (from) -> String.valueOf(from + num); num = 3;
การเข้าถึงฟิลด์อินสแตนซ์และตัวแปรทางสถิติ
ต่างจากตัวแปรภายในเครื่อง เราสามารถอ่านและเปลี่ยนแปลงฟิลด์อินสแตนซ์และตัวแปรทางสถิติภายในนิพจน์แลมบ์ดาได้ เราทราบพฤติกรรมนี้จากวัตถุที่ไม่ระบุชื่อ class Lambda4 { static int outerStaticNum; int outerNum; void testScopes() { Converter stringConverter1 = (from) -> { outerNum = 23; return String.valueOf(from); }; Converter stringConverter2 = (from) -> { outerStaticNum = 72; return String.valueOf(from); }; } }
เข้าถึงวิธีการเริ่มต้นของอินเทอร์เฟซ
จำตัวอย่างที่มี อินสแตนซ์ สูตรจากส่วนแรกได้ไหม อิน เทอร์เฟซสูตรกำหนด วิธี sqrt เริ่มต้น ที่สามารถเข้าถึงได้จากทุกอินสแตนซ์ของ สูตรรวมถึงวัตถุที่ไม่ระบุชื่อ สิ่งนี้ใช้ไม่ได้กับนิพจน์แลมบ์ดา ไม่สามารถเข้าถึงวิธีการเริ่มต้นภายในนิพจน์แลมบ์ดา รหัสต่อไปนี้ไม่ได้รวบรวม: Formula formula = (a) -> sqrt( a * 100);

อินเทอร์เฟซการทำงานในตัว

JDK 1.8 API มีอินเทอร์เฟซการทำงานในตัวมากมาย บางส่วนเป็นที่รู้จักจาก Java เวอร์ชันก่อนหน้า ตัวอย่างเช่น Comparatorหรือ Runnable อินเทอร์เฟซเหล่านี้ได้รับการขยายเพื่อรวมการรองรับแลมบ์ดาโดยใช้ คำอธิบาย ประกอบ @FunctionalInterface แต่ Java 8 API ยังเต็มไปด้วยอินเทอร์เฟซการทำงานใหม่ๆ ที่จะทำให้ชีวิตของคุณง่ายขึ้น อินเทอร์เฟซ บางส่วนเหล่านี้เป็นที่รู้จักจาก ไลบรารี Guava ของ Google แม้ว่าคุณจะคุ้นเคยกับไลบรารีนี้แล้ว คุณควรพิจารณาวิธีการขยายอินเทอร์เฟซเหล่านี้ให้ละเอียดยิ่งขึ้น พร้อมวิธีการขยายที่มีประโยชน์บางอย่าง
ภาคแสดง
เพรดิเคตคือฟังก์ชันบูลีนที่มีหนึ่งอาร์กิวเมนต์ อินเทอร์เฟซประกอบด้วยวิธีการเริ่มต้นต่างๆ สำหรับการสร้างนิพจน์เชิงตรรกะที่ซับซ้อน (และหรือลบล้าง) โดยใช้เพรดิเคต Predicate predicate = (s) -> s.length() > 0; predicate.test("foo"); // true predicate.negate().test("foo"); // false Predicate nonNull = Objects::nonNull; Predicate isNull = Objects::isNull; Predicate isEmpty = String::isEmpty; Predicate isNotEmpty = isEmpty.negate();
ฟังก์ชั่น
ฟังก์ชันรับหนึ่งอาร์กิวเมนต์และสร้างผลลัพธ์ วิธีการเริ่มต้นสามารถใช้เพื่อรวมหลายฟังก์ชันเข้าด้วยกันเป็นสายโซ่เดียว (เขียนแล้ว) Function toInteger = Integer::valueOf; Function backToString = toInteger.andThen(String::valueOf); backToString.apply("123"); // "123"
ซัพพลายเออร์
ซัพพลายเออร์ส่งคืนผลลัพธ์ (อินสแตนซ์) ประเภทใดประเภทหนึ่ง ต่างจากฟังก์ชันตรงที่ผู้ให้บริการไม่รับข้อโต้แย้ง Supplier personSupplier = Person::new; personSupplier.get(); // new Person
ผู้บริโภค
ผู้บริโภคเป็นตัวแทนของวิธีการอินเทอร์เฟซด้วยอาร์กิวเมนต์เดียว Consumer greeter = (p) -> System.out.println("Hello, " + p.firstName); greeter.accept(new Person("Luke", "Skywalker"));
เครื่องเปรียบเทียบ
เรารู้จักเครื่องมือเปรียบเทียบจาก Java เวอร์ชันก่อนหน้า Java 8 ช่วยให้คุณสามารถเพิ่มวิธีการเริ่มต้นต่างๆ ให้กับอินเทอร์เฟซได้ Comparator comparator = (p1, p2) -> p1.firstName.compareTo(p2.firstName); Person p1 = new Person("John", "Doe"); Person p2 = new Person("Alice", "Wonderland"); comparator.compare(p1, p2); // > 0 comparator.reversed().compare(p1, p2); // < 0
ทางเลือก
อินเทอร์เฟซ Optionals ไม่ทำงาน แต่เป็นยูทิลิตี้ที่ดีเยี่ยมในการป้องกัน NullPointerException นี่เป็นจุดสำคัญสำหรับส่วนถัดไป ดังนั้นเรามาดูกันว่าอินเทอร์เฟซนี้ทำงานอย่างไรโดยสรุป อินเทอร์เฟซเสริมเป็นคอนเทนเนอร์อย่างง่ายสำหรับค่าที่สามารถเป็น โมฆะหรือไม่ใช่โมฆะได้ ลองนึกภาพว่าวิธีการสามารถส่งกลับค่าหรือไม่มีอะไรเลย ใน Java 8 แทนที่จะส่งคืน nullคุณจะส่งคืนOptional instance Comparator comparator = (p1, p2) -> p1.firstName.compareTo(p2.firstName); Person p1 = new Person("John", "Doe"); Person p2 = new Person("Alice", "Wonderland"); comparator.compare(p1, p2); // > 0 comparator.reversed().compare(p1, p2); // < 0

ลำธาร

java.util.Streamเป็นลำดับขององค์ประกอบที่มีการดำเนินการหนึ่งรายการหรือหลายรายการ การดำเนินการ Stream แต่ละรายการเป็นแบบสื่อกลางหรือเทอร์มินัล การดำเนินการเทอร์มินัลส่งคืนผลลัพธ์เป็นประเภทเฉพาะ ในขณะที่การดำเนินการระดับกลางส่งคืนออบเจ็กต์สตรีมเอง ทำให้สามารถสร้างการเรียกเมธอดลูกโซ่ได้ Stream เป็นอินเทอร์เฟซ เช่น java.util.Collectionสำหรับรายการและชุด (ไม่รองรับแผนที่) การดำเนินการ Stream แต่ละรายการสามารถดำเนินการตามลำดับหรือแบบขนานได้ มาดูกันว่าสตรีมทำงานอย่างไร ขั้นแรก เราจะสร้างโค้ดตัวอย่างในรูปแบบของรายการสตริง: คอลเลกชั่นใน Java 8 ได้ รับการปรับปรุงเพื่อให้คุณสามารถสร้างสตรีมได้ง่ายๆ โดยการเรียก Collection.stream()หรือ Collection.parallelStream() หัวข้อถัดไปจะอธิบายการดำเนินการสตรีมแบบง่ายที่สำคัญที่สุด List stringCollection = new ArrayList<>(); stringCollection.add("ddd2"); stringCollection.add("aaa2"); stringCollection.add("bbb1"); stringCollection.add("aaa1"); stringCollection.add("bbb3"); stringCollection.add("ccc"); stringCollection.add("bbb2"); stringCollection.add("ddd1");
กรอง
ตัวกรองยอมรับเพรดิเคตเพื่อกรององค์ประกอบทั้งหมดของสตรีม การดำเนินการนี้เป็นการดำเนินการระดับกลาง ซึ่งช่วยให้เราสามารถเรียกใช้การดำเนินการสตรีมอื่นๆ (เช่น forEach) กับผลลัพธ์ผลลัพธ์ (กรองแล้ว) ForEach ยอมรับการดำเนินการที่จะดำเนินการกับแต่ละองค์ประกอบของสตรีมที่กรองแล้ว ForEach เป็นการดำเนินการเทอร์มินัล นอกจากนี้ การเรียกการดำเนินการอื่นๆ ยังเป็นไปไม่ได้ stringCollection .stream() .filter((s) -> s.startsWith("a")) .forEach(System.out::println); // "aaa2", "aaa1"
จัดเรียง
Sorted เป็นการดำเนินการระดับกลางที่ส่งคืนการแสดงสตรีมที่เรียงลำดับแล้ว องค์ประกอบจะถูกจัดเรียงตามลำดับที่ถูกต้อง เว้นแต่คุณจะระบุตัว เปรียบเทียบ stringCollection .stream() .sorted() .filter((s) -> s.startsWith("a")) .forEach(System.out::println); // "aaa1", "aaa2" โปรดทราบว่าการเรียงลำดับจะสร้างการแสดงสตรีมที่เรียงลำดับโดยไม่ส่งผลกระทบต่อคอลเลกชัน ลำดับของ องค์ประกอบ stringCollectionยังคงไม่ถูกแตะต้อง: System.out.println(stringCollection); // ddd2, aaa2, bbb1, aaa1, bbb3, ccc, bbb2, ddd1
แผนที่
การดำเนินการแผนที่ระดับกลางจะแปลงแต่ละองค์ประกอบให้เป็นวัตถุอื่นโดยใช้ฟังก์ชันผลลัพธ์ ตัวอย่างต่อไปนี้จะแปลงแต่ละสตริงเป็นสตริงตัวพิมพ์ใหญ่ แต่คุณยังสามารถใช้แผนที่เพื่อแปลงแต่ละวัตถุให้เป็นประเภทอื่นได้ ประเภทของออบเจ็กต์สตรีมผลลัพธ์จะขึ้นอยู่กับประเภทของฟังก์ชันที่คุณส่งไปยังแมป stringCollection .stream() .map(String::toUpperCase) .sorted((a, b) -> b.compareTo(a)) .forEach(System.out::println); // "DDD2", "DDD1", "CCC", "BBB3", "BBB2", "AAA2", "AAA1"
จับคู่
การดำเนินการจับคู่ต่างๆ สามารถใช้เพื่อทดสอบความจริงของภาคแสดงเฉพาะในความสัมพันธ์ของกระแสข้อมูล การดำเนินการจับคู่ทั้งหมดเป็นเทอร์มินัลและส่งกลับผลลัพธ์แบบบูลีน boolean anyStartsWithA = stringCollection .stream() .anyMatch((s) -> s.startsWith("a")); System.out.println(anyStartsWithA); // true boolean allStartsWithA = stringCollection .stream() .allMatch((s) -> s.startsWith("a")); System.out.println(allStartsWithA); // false boolean noneStartsWithZ = stringCollection .stream() .noneMatch((s) -> s.startsWith("z")); System.out.println(noneStartsWithZ); // true
นับ
Count คือการดำเนินการเทอร์มินัลที่ส่งคืนจำนวนองค์ประกอบของสตรีมในรูปแบบ ยาว long startsWithB = stringCollection .stream() .filter((s) -> s.startsWith("b")) .count(); System.out.println(startsWithB); // 3
ลด
นี่คือการดำเนินการเทอร์มินัลที่ทำให้องค์ประกอบของสตรีมสั้นลงโดยใช้ฟังก์ชันที่ส่งผ่าน ผลลัพธ์จะเป็น ตัวเลือกที่มีค่าย่อลง Optional reduced = stringCollection .stream() .sorted() .reduce((s1, s2) -> s1 + "#" + s2); reduced.ifPresent(System.out::println); // "aaa1#aaa2#bbb1#bbb2#bbb3#ccc#ddd1#ddd2"

ลำธารคู่ขนาน

ตามที่กล่าวไว้ข้างต้น สตรีมอาจเป็นแบบต่อเนื่องหรือแบบขนานก็ได้ การดำเนินการสตรีมตามลำดับจะดำเนินการบนเธรดแบบอนุกรม ในขณะที่การดำเนินการสตรีมแบบขนานจะดำเนินการบนเธรดแบบขนานหลายรายการ ตัวอย่างต่อไปนี้สาธิตวิธีการเพิ่มประสิทธิภาพอย่างง่ายดายโดยใช้สตรีมแบบขนาน ขั้นแรก เรามาสร้างรายการองค์ประกอบที่ไม่ซ้ำกันจำนวนมาก: ตอนนี้เราจะกำหนดเวลาที่ใช้ในการเรียงลำดับสตรีมของคอลเลกชันนี้ int max = 1000000; List values = new ArrayList<>(max); for (int i = 0; i < max; i++) { UUID uuid = UUID.randomUUID(); values.add(uuid.toString()); }
สตรีมแบบอนุกรม
long t0 = System.nanoTime(); long count = values.stream().sorted().count(); System.out.println(count); long t1 = System.nanoTime(); long millis = TimeUnit.NANOSECONDS.toMillis(t1 - t0); System.out.println(String.format("sequential sort took: %d ms", millis)); // sequential sort took: 899 ms
กระแสขนาน
long t0 = System.nanoTime(); long count = values.parallelStream().sorted().count(); System.out.println(count); long t1 = System.nanoTime(); long millis = TimeUnit.NANOSECONDS.toMillis(t1 - t0); System.out.println(String.format("parallel sort took: %d ms", millis)); // parallel sort took: 472 ms อย่างที่คุณเห็น ทั้งสองส่วนเกือบจะเหมือนกัน แต่การเรียงลำดับแบบขนานนั้นเร็วกว่า 50% สิ่งที่คุณต้องมีคือเปลี่ยน stream()เป็น parallelStream( )

แผนที่

ตามที่ได้กล่าวไปแล้ว แผนที่ไม่รองรับการสตรีม แต่ map เริ่มสนับสนุนวิธีการใหม่และมีประโยชน์ในการแก้ปัญหาทั่วไปแทน โค้ดด้านบนควรใช้งานง่าย: putIfAbsentเตือนเราไม่ให้เขียนการตรวจสอบที่เป็นโมฆะเพิ่มเติม forEachยอมรับฟังก์ชันที่จะดำเนินการกับค่าแผนที่แต่ละค่า ตัวอย่างนี้แสดงวิธีดำเนินการกับค่าแผนที่โดยใช้ฟังก์ชัน: ต่อไปเราจะเรียนรู้วิธีลบรายการสำหรับคีย์ที่กำหนดเฉพาะในกรณีที่แมปกับค่าที่กำหนด: อีกวิธีที่ดี: การรวมรายการแผนที่นั้นค่อนข้างง่าย: การรวม จะแทรกคีย์/ค่าลงในแผนที่ หากไม่มีรายการสำหรับคีย์ที่กำหนด หรือฟังก์ชันผสานจะถูกเรียก ซึ่งจะเปลี่ยนค่าของรายการที่มีอยู่ Map map = new HashMap<>(); for (int i = 0; i < 10; i++) { map.putIfAbsent(i, "val" + i); } map.forEach((id, val) -> System.out.println(val)); map.computeIfPresent(3, (num, val) -> val + num); map.get(3); // val33 map.computeIfPresent(9, (num, val) -> null); map.containsKey(9); // false map.computeIfAbsent(23, num -> "val" + num); map.containsKey(23); // true map.computeIfAbsent(3, num -> "bam"); map.get(3); // val33 map.remove(3, "val3"); map.get(3); // val33 map.remove(3, "val33"); map.get(3); // null map.getOrDefault(42, "not found"); // not found map.merge(9, "val9", (value, newValue) -> value.concat(newValue)); map.get(9); // val9 map.merge(9, "concat", (value, newValue) -> value.concat(newValue)); map.get(9); // val9concat
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION