Java 9 แนะนำวิธีการโรงงานใหม่สำหรับรายการList.of:
List<String> strings = List.of("first", "second");
ตัวเลือกก่อนหน้าและตัวเลือกใหม่แตกต่างกันอย่างไร นั่นคือความแตกต่างระหว่างสิ่งนี้คืออะไร:
Arrays.asList(1, 2, 3);
และนี่:
List.of(1, 2, 3);
Java 9 แนะนำวิธีการโรงงานใหม่สำหรับรายการList.of:
List<String> strings = List.of("first", "second");
ตัวเลือกก่อนหน้าและตัวเลือกใหม่แตกต่างกันอย่างไร นั่นคือความแตกต่างระหว่างสิ่งนี้คืออะไร:
Arrays.asList(1, 2, 3);
และนี่:
List.of(1, 2, 3);
คำตอบ:
Arrays.asListส่งกลับรายการที่ไม่แน่นอนในขณะที่รายชื่อที่ส่งกลับโดยList.ofเป็นไม่เปลี่ยนรูป :
List<Integer> list = Arrays.asList(1, 2, null);
list.set(1, 10); // OK
List<Integer> list = List.of(1, 2, 3);
list.set(1, 10); // Fails with UnsupportedOperationException
Arrays.asListอนุญาตองค์ประกอบว่างในขณะที่List.ofไม่:
List<Integer> list = Arrays.asList(1, 2, null); // OK
List<Integer> list = List.of(1, 2, null); // Fails with NullPointerException
contains ทำงานแตกต่างกับ nulls:
List<Integer> list = Arrays.asList(1, 2, 3);
list.contains(null); // Returns false
List<Integer> list = List.of(1, 2, 3);
list.contains(null); // Fails with NullPointerException
Arrays.asListส่งคืนมุมมองของอาร์เรย์ที่ส่งผ่านดังนั้นการเปลี่ยนแปลงในอาร์เรย์จะปรากฏในรายการด้วย สำหรับList.ofสิ่งนี้ไม่เป็นความจริง:
Integer[] array = {1,2,3};
List<Integer> list = Arrays.asList(array);
array[1] = 10;
System.out.println(list); // Prints [1, 10, 3]
Integer[] array = {1,2,3};
List<Integer> list = List.of(array);
array[1] = 10;
System.out.println(list); // Prints [1, 2, 3]
List.contains(Object o)javadoc ของ : "Throws [... ] NullPointerException - หากองค์ประกอบที่ระบุเป็นโมฆะและรายการนี้ไม่อนุญาตให้ใช้องค์ประกอบ null (ทางเลือก)" หรือจากการแนะนำแบบยาวของอินเทอร์เฟซที่มีเพียงไม่กี่คนที่อ่าน: "การใช้งานคอลเล็กชันบางอย่างมีข้อ จำกัด เกี่ยวกับองค์ประกอบที่อาจมี"
List.of ไม่กลับบางImmutableListชนิดชื่อจริงของมันเป็นเพียงรายละเอียดการดำเนินงานที่ไม่ใช่แบบสาธารณะ ถ้าเป็นสาธารณะและมีคนแคสต์ไปListอีกครั้งความแตกต่างอยู่ตรงไหน? อะไรคือความแตกต่างArrays.asListซึ่งส่งคืนการใช้งานที่ไม่เปิดเผยต่อสาธารณะListที่ทำให้เกิดข้อยกเว้นเมื่อพยายามaddหรือremoveหรือรายการที่ส่งคืนโดยCollections.unmodifiableListที่ไม่อนุญาตให้แก้ไขเลย ทุกอย่างเกี่ยวกับสัญญาที่ระบุไว้ในListอินเทอร์เฟซ Collections อินเทอร์เฟซกับเมธอดเสริมมักไม่บริสุทธิ์ OOP ตั้งแต่ Java 1.2 …
Arrays.asListและList.ofดูJavaDocsและคำพูดนี้โดย Stuart Marks (หรือเวอร์ชันก่อนหน้า)
ฉันจะใช้สิ่งต่อไปนี้สำหรับตัวอย่างโค้ด:
List<Integer> listOf = List.of(...);
List<Integer> asList = Arrays.asList(...);
List<Integer> unmodif = Collections.unmodifiableList(asList);
ความพยายามใด ๆ ในการเปลี่ยนแปลงเชิงโครงสร้างList.ofจะส่งผลให้UnsupportedOperationExceptionไฟล์. ซึ่งรวมถึงการดำเนินการเช่นการเพิ่ม , ชุดและลบ อย่างไรก็ตามคุณสามารถเปลี่ยนเนื้อหาของวัตถุในรายการได้ (หากวัตถุไม่เปลี่ยนรูป) ดังนั้นรายการจึงไม่ "ไม่เปลี่ยนรูปโดยสิ้นเชิง"
นี่คือชะตากรรมเดียวกันสำหรับรายการ unmodifiable Collections.unmodifiableListสร้างขึ้นด้วย รายการนี้เท่านั้นที่เป็นมุมมองของรายการต้นฉบับดังนั้นจึงสามารถเปลี่ยนแปลงได้หากคุณเปลี่ยนรายการเดิม
Arrays.asListไม่ได้เปลี่ยนรูปสมบูรณ์ก็ไม่ได้มีข้อ จำกัด setในการ
listOf.set(1, "a"); // UnsupportedOperationException
unmodif.set(1, "a"); // UnsupportedOperationException
asList.set(1, "a"); // modified unmodif! unmodif is not truly unmodifiable
ในทำนองเดียวกันการเปลี่ยนอาร์เรย์สำรอง (ถ้าคุณถือไว้) จะเปลี่ยนรายการ
ความไม่เปลี่ยนรูปของโครงสร้างมาพร้อมกับผลข้างเคียงมากมายที่เกี่ยวข้องกับการเข้ารหัสป้องกันภาวะพร้อมกันและความปลอดภัยซึ่งอยู่นอกเหนือขอบเขตของคำตอบนี้
List.ofและคอลเลกชันใด ๆ ตั้งแต่ Java 1.5 ไม่อนุญาตให้nullเป็นองค์ประกอบ การพยายามส่งผ่านnullเป็นองค์ประกอบหรือแม้แต่การค้นหาจะส่งผลให้ไฟล์NullPointerException.
เนื่องจากArrays.asListเป็นคอลเล็กชันจาก 1.2 (Collections Framework) จึงอนุญาตให้nulls
listOf.contains(null); // NullPointerException
unmodif.contains(null); // allowed
asList.contains(null); // allowed
เนื่องจากList.ofได้รับการแนะนำใน Java 9 และรายการที่สร้างโดยวิธีนี้มีรูปแบบอนุกรม (ไบนารี) เป็นของตัวเองจึงไม่สามารถ deserialized ใน JDK เวอร์ชันก่อนหน้านี้ได้ (ไม่มีความเข้ากันได้แบบไบนารี ) อย่างไรก็ตามคุณสามารถ de / serialize ด้วย JSON ได้เช่น
Arrays.asListการโทรภายในnew ArrayListซึ่งรับประกันความไม่เท่าเทียมกันในการอ้างอิง
List.ofขึ้นอยู่กับการใช้งานภายใน อินสแตนซ์ที่ส่งคืนอาจมีความเท่าเทียมกันในการอ้างอิง แต่เนื่องจากไม่รับประกันว่าคุณไม่สามารถวางใจได้
asList1 == asList2; // false
listOf1 == listOf2; // true or false
ควรค่าแก่การกล่าวถึงว่ารายการมีค่าเท่ากัน (ผ่านList.equals) หากมีองค์ประกอบเดียวกันในลำดับเดียวกันไม่ว่าจะสร้างขึ้นอย่างไรหรือสนับสนุนการดำเนินการใดก็ตาม
asList.equals(listOf); // true i.f.f. same elements in same order
หากจำนวนองค์ประกอบในรายการList.of2 หรือน้อยกว่าองค์ประกอบจะถูกเก็บไว้ในฟิลด์ของคลาสพิเศษ (ภายใน) ตัวอย่างคือรายการที่เก็บ 2 องค์ประกอบ (ที่มาบางส่วน):
static final class List2<E> extends AbstractImmutableList<E> {
private final E e0;
private final E e1;
List2(E e0, E e1) {
this.e0 = Objects.requireNonNull(e0);
this.e1 = Objects.requireNonNull(e1);
}
}
Arrays.asListมิฉะนั้นพวกเขาจะถูกเก็บไว้ในอาร์เรย์ในลักษณะคล้ายกับ
การList.ofใช้งานที่อิงตามภาคสนาม (ขนาด <2) จะทำงานได้เร็วขึ้นเล็กน้อยในการดำเนินการบางอย่าง ดังตัวอย่างsize()สามารถส่งคืนค่าคงที่โดยไม่ต้องดึงความยาวอาร์เรย์และcontains(E e)ไม่จำเป็นต้องมีค่าใช้จ่ายในการวนซ้ำ
การสร้างรายการที่ไม่สามารถแก้ไขได้ผ่านทางList.ofนั้นเร็วกว่าด้วย เปรียบเทียบตัวสร้างข้างต้นกับการกำหนดอ้างอิง 2 รายการ (และแม้แต่ตัวสร้างสำหรับจำนวนองค์ประกอบโดยพลการ) กับ
Collections.unmodifiableList(Arrays.asList(...));
ซึ่งสร้าง 2 รายการพร้อมค่าใช้จ่ายอื่น ๆ ในแง่ของพื้นที่คุณสามารถประหยัดUnmodifiableListกระดาษห่อหุ้มและเหรียญเพนนี ท้ายที่สุดแล้วการประหยัดที่HashSetเทียบเท่านั้นน่าเชื่อกว่า
เวลาสรุป: ใช้List.ofเมื่อคุณต้องการรายการที่ไม่เปลี่ยนแปลงและArrays.asListเมื่อคุณต้องการรายการที่สามารถเปลี่ยนแปลงได้ (ดังแสดงด้านบน)
Arrays.asListไม่เปลี่ยนแปลงอย่างสมบูรณ์ asList.add(1);พ่นUnsupportedOperationExceptionไฟล์.
List.ofเวลาใด ๆ ที่ผู้คนอาจต้องการโทรcontainsและไม่ต้องแปลกใจกับ NullPointerException
ให้สรุปความแตกต่างระหว่างList.ofและArrays.asList
List.ofสามารถใช้งานได้ดีที่สุดเมื่อชุดข้อมูลน้อยลงและไม่มีการเปลี่ยนแปลงในขณะที่Arrays.asListสามารถใช้ได้ดีที่สุดในกรณีของชุดข้อมูลขนาดใหญ่และไดนามิก
List.ofใช้พื้นที่เหนือศีรษะน้อยมากเนื่องจากมีการใช้งานตามภาคสนามและใช้พื้นที่ฮีปน้อยทั้งในแง่ของค่าโสหุ้ยคงที่และแบบต่อองค์ประกอบ ในขณะที่Arrays.asListใช้พื้นที่เหนือศีรษะมากขึ้นเนื่องจากในขณะที่เริ่มต้นจะสร้างวัตถุเพิ่มเติมในฮีป
คอลเล็กชันที่ส่งคืนโดยList.ofไม่เปลี่ยนรูปและด้วยเหตุนี้จึงปลอดภัยต่อเธรดในขณะที่คอลเล็กชันที่ส่งคืนโดยArrays.asListไม่แน่นอนและไม่ปลอดภัยต่อเธรด (โดยทั่วไปแล้วอินสแตนซ์คอลเลคชันที่ไม่เปลี่ยนรูปจะใช้หน่วยความจำน้อยกว่าอินสแตนซ์ที่ไม่สามารถเปลี่ยนแปลงได้)
List.ofไม่อนุญาตองค์ประกอบnullในขณะที่Arrays.asListอนุญาตองค์ประกอบnull
Arrays.asListเมื่อเทียบกับList.ofเนื่องจากอดีตเป็นเพียงกระดาษห่อหุ้มรอบอาร์เรย์ อย่างน้อยการใช้งาน OpenJDKดูเหมือนว่าจะมีค่าใช้จ่ายที่น้อยมาก ในความเป็นจริงList.ofจะต้องทำสำเนาของอาร์เรย์ใด ๆ ที่ส่งผ่านดังนั้นเว้นแต่ว่าอาร์เรย์จะเป็น GC ในเร็ว ๆ นี้ดูเหมือนว่าจะList.ofมีขนาดหน่วยความจำที่ใหญ่กว่ามาก
List.of(x)และList.of(x, y)มีประสิทธิภาพมากขึ้นเพราะไม่จัดสรรอาร์เรย์เลย
List.ofวิธีนี้ไม่จำเป็นต้องส่งคืนรายการใหม่ทุกครั้ง รายการเหล่านี้มีข้อมูลประจำตัวที่ไม่ระบุดังนั้นจึงอาจมีการจัดการแคชหรือการคัดลอกข้อมูลซ้ำซ้อนหรือการปรับสเกลาร์ในระดับ JVM หากไม่ได้อยู่ในเวอร์ชันนี้อาจเป็นในครั้งต่อไป ได้รับอนุญาตตามสัญญา ในทางตรงกันข้ามArray.asListขึ้นอยู่กับข้อมูลประจำตัวของอาร์เรย์ที่คุณส่งผ่านเนื่องจากรายการผลลัพธ์เป็นมุมมองที่ไม่แน่นอนบนอาร์เรย์ซึ่งสะท้อนถึงการเปลี่ยนแปลงทั้งหมดแบบสองทิศทาง
นอกเหนือจากคำตอบข้างต้นมีการดำเนินการบางอย่างที่ทั้งสองList::ofและArrays::asListแตกต่างกัน:
+----------------------+---------------+----------+----------------+---------------------+
| Operations | SINGLETONLIST | LIST::OF | ARRAYS::ASLIST | JAVA.UTIL.ARRAYLIST |
+----------------------+---------------+----------+----------------+---------------------+
| add | ❌ | ❌ | ❌ | ✔️ |
+----------------------+---------------+----------+----------------+---------------------+
| addAll | ❌ | ❌ | ❌ | ✔️ |
+----------------------+---------------+----------+----------------+---------------------+
| clear | ❌ | ❌ | ❌ | ✔️ |
+----------------------+---------------+----------+----------------+---------------------+
| remove | ❌ | ❌ | ❌ | ✔️ |
+----------------------+---------------+----------+----------------+---------------------+
| removeAll | ❗️ | ❌ | ❗️ | ✔️ |
+----------------------+---------------+----------+----------------+---------------------+
| retainAll | ❗️ | ❌ | ❗️ | ✔️ |
+----------------------+---------------+----------+----------------+---------------------+
| replaceAll | ❌ | ❌ | ✔️ | ✔️ |
+----------------------+---------------+----------+----------------+---------------------+
| set | ❌ | ❌ | ✔️ | ✔️ |
+----------------------+---------------+----------+----------------+---------------------+
| sort | ✔️ | ❌ | ✔️ | ✔️ |
+----------------------+---------------+----------+----------------+---------------------+
| remove on iterator | ❌ | ❌ | ❌ | ✔️ |
+----------------------+---------------+----------+----------------+---------------------+
| set on list-iterator | ❌ | ❌ | ✔️ | ✔️ |
+----------------------+---------------+----------+----------------+---------------------+
เพิ่มเติมเกี่ยวกับคอลเลกชัน :: singletonList Vs. รายการของ