Xem JavaDocs và bài nói chuyện này của Stuart Marks (hoặc các phiên bản trước của nó).
Tôi sẽ sử dụng phần sau cho các ví dụ mã:
List<Integer> listOf = List.of(...);
List<Integer> asList = Arrays.asList(...);
List<Integer> unmodif = Collections.unmodifiableList(asList);
Tính bất biến của cấu trúc (Hoặc: tính không thay đổi)
Bất kỳ nỗ lực nào để thay đổi cấu trúcList.of
sẽ dẫn đến UnsupportedOperationException
. Điều đó bao gồm các hoạt động như thêm , đặt và loại bỏ . Tuy nhiên, bạn có thể thay đổi nội dung của các đối tượng trong danh sách (nếu các đối tượng không phải là bất biến), do đó, danh sách không phải là "hoàn toàn bất biến".
Đây cũng là số phận đối với danh sách không thể sửa đổi được tạo bằng Collections.unmodifiableList
. Chỉ có danh sách này là chế độ xem của danh sách gốc, vì vậy nó có thể thay đổi nếu bạn thay đổi danh sách ban đầu.
Arrays.asList
không phải là bất biến hoàn toàn, nó không có hạn chế set
.
listOf.set(1, "a"); // UnsupportedOperationException
unmodif.set(1, "a"); // UnsupportedOperationException
asList.set(1, "a"); // modified unmodif! unmodif is not truly unmodifiable
Tương tự, thay đổi mảng ủng hộ (nếu bạn giữ nó) sẽ thay đổi danh sách.
Tính bất biến của cấu trúc đi kèm với nhiều tác dụng phụ liên quan đến mã hóa phòng thủ, đồng thời và bảo mật nằm ngoài phạm vi của câu trả lời này.
Thù địch vô nghĩa
List.of
và bất kỳ bộ sưu tập nào kể từ Java 1.5 không cho phép null
dưới dạng một phần tử. Cố gắng vượt qua null
dưới dạng một phần tử hoặc thậm chí là tra cứu sẽ dẫn đến một NullPointerException
.
Vì Arrays.asList
là một tập hợp từ 1.2 (Khung Bộ sưu tập), nó cho phép null
s.
listOf.contains(null); // NullPointerException
unmodif.contains(null); // allowed
asList.contains(null); // allowed
Biểu mẫu được tuần tự hóa
Kể từ khi List.of
được giới thiệu trong Java 9 và các danh sách được tạo bằng phương pháp này có dạng tuần tự hóa (nhị phân) của riêng chúng, chúng không thể được giải mã trên các phiên bản JDK trước đó (không có khả năng tương thích nhị phân ). Tuy nhiên, bạn có thể hủy / tuần tự hóa bằng JSON, chẳng hạn.
Danh tính
Arrays.asList
cuộc gọi nội bộ new ArrayList
, đảm bảo bất bình đẳng tham chiếu.
List.of
phụ thuộc vào việc thực hiện nội bộ. Các trường hợp trả về có thể có tham chiếu bình đẳng, nhưng vì điều này không được đảm bảo nên bạn không thể dựa vào nó.
asList1 == asList2; // false
listOf1 == listOf2; // true or false
Đáng nói là danh sách là bằng nhau (thông qua List.equals
) nếu chúng chứa các phần tử giống nhau theo cùng một thứ tự, bất kể chúng được tạo ra như thế nào hoặc chúng hỗ trợ hoạt động nào.
asList.equals(listOf); // true i.f.f. same elements in same order
Triển khai (cảnh báo: chi tiết có thể thay đổi qua các phiên bản)
Nếu số phần tử trong danh sách List.of
là 2 hoặc ít hơn, các phần tử được lưu trữ trong các trường của một lớp chuyên biệt (nội bộ). Một ví dụ là danh sách lưu trữ 2 phần tử (một phần nguồn):
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);
}
}
Nếu không, chúng được lưu trữ trong một mảng theo kiểu tương tự như Arrays.asList
.
Hiệu quả về thời gian và không gian
Các List.of
triển khai dựa trên trường (kích thước <2) thực hiện nhanh hơn một chút đối với một số hoạt động. Ví dụ: size()
có thể trả về một hằng số mà không cần tìm nạp độ dài mảng và contains(E e)
không yêu cầu chi phí lặp lại.
Việc tạo danh sách không thể sửa đổi thông qua List.of
cũng nhanh hơn. So sánh hàm tạo ở trên với 2 phép gán tham chiếu (và thậm chí là phép gán cho số lượng phần tử tùy ý) để
Collections.unmodifiableList(Arrays.asList(...));
tạo 2 danh sách cộng với chi phí khác. Về không gian, bạn tiết kiệm được UnmodifiableList
trình bao bọc cộng với một số xu. Cuối cùng, số tiền tiết kiệm HashSet
tương đương được thuyết phục hơn.
Thời gian kết luận: sử dụng List.of
khi bạn muốn một danh sách không thay đổi và Arrays.asList
khi bạn muốn một danh sách có thể thay đổi (như hình trên).