Zobacz JavaDocs i ten wykład autorstwa Stuarta Marksa (lub jego poprzednich wersji).
Będę używał następujących przykładów kodu:
List<Integer> listOf = List.of(...);
List<Integer> asList = Arrays.asList(...);
List<Integer> unmodif = Collections.unmodifiableList(asList);
Niezmienność strukturalna (lub: niemodyfikowalność)
Każda próba zmiany strukturalnejList.of
spowoduje, że plik UnsupportedOperationException
. Obejmuje to operacje takie jak dodawanie , ustawianie i usuwanie . Możesz jednak zmienić zawartość obiektów na liście (jeśli obiekty nie są niezmienne), więc lista nie jest „całkowicie niezmienna”.
To samo dotyczy niemodyfikowalnych list utworzonych za pomocą Collections.unmodifiableList
. Tylko ta lista jest widokiem oryginalnej listy, więc może się zmienić, jeśli zmienisz oryginalną listę.
Arrays.asList
nie jest całkowicie niezmienna, nie ma ograniczeń set
.
listOf.set(1, "a"); // UnsupportedOperationException
unmodif.set(1, "a"); // UnsupportedOperationException
asList.set(1, "a"); // modified unmodif! unmodif is not truly unmodifiable
Podobnie zmiana tablicy bazowej (jeśli ją przytrzymasz) spowoduje zmianę listy.
Niezmienność strukturalna wiąże się z wieloma skutkami ubocznymi związanymi z kodowaniem obronnym, współbieżnością i bezpieczeństwem, które wykraczają poza zakres tej odpowiedzi.
Zerowa wrogość
List.of
i wszystkie kolekcje od wersji Java 1.5 nie pozwalają null
jako element. Próba przekazania null
jako elementu lub nawet wyszukiwania spowoduje utworzenie pliku NullPointerException
.
Ponieważ Arrays.asList
jest to kolekcja z wersji 1.2 (struktura kolekcji), umożliwia null
s.
listOf.contains(null); // NullPointerException
unmodif.contains(null); // allowed
asList.contains(null); // allowed
Formularz serializowany
Ponieważ List.of
została wprowadzona w Javie 9, a listy utworzone za pomocą tej metody mają własną (binarną) zserializowaną postać, nie można ich deserializować we wcześniejszych wersjach JDK (brak zgodności binarnej ). Możesz jednak na przykład de / serializować za pomocą JSON.
Tożsamość
Arrays.asList
wywołania wewnętrzne new ArrayList
, co gwarantuje nierówność odniesień.
List.of
zależy od implementacji wewnętrznej. Zwrócone instancje mogą mieć równość odwołań, ale ponieważ nie jest to gwarantowane, nie można na nich polegać.
asList1 == asList2; // false
listOf1 == listOf2; // true or false
Warto wspomnieć, że listy są równe (via List.equals
), jeśli zawierają te same elementy w tej samej kolejności, niezależnie od tego, jak zostały utworzone lub jakie operacje obsługują.
asList.equals(listOf); // true i.f.f. same elements in same order
Implementacja (ostrzeżenie: szczegóły mogą ulec zmianie w przypadku wersji)
Jeśli liczba elementów na liście List.of
wynosi 2 lub mniej, elementy są przechowywane w polach wyspecjalizowanej (wewnętrznej) klasy. Przykładem jest lista przechowująca 2 elementy (częściowe źródło):
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);
}
}
W przeciwnym razie są przechowywane w tablicy w podobny sposób jak Arrays.asList
.
Efektywność czasu i przestrzeni
W List.of
implementacji, które są oparte na polu (wielkość <2) nieznacznie szybciej wykonywać niektóre operacje. Na przykład size()
może zwrócić stałą bez pobierania długości tablicy i contains(E e)
nie wymaga narzutu iteracji.
Tworzenie niemodyfikowalnej listy przez List.of
jest również szybsze. Porównaj powyższy konstruktor z 2 przypisaniami referencyjnymi (a nawet jednym dla dowolnej liczby elementów) do
Collections.unmodifiableList(Arrays.asList(...));
co tworzy 2 listy plus inne narzuty. Jeśli chodzi o miejsce, oszczędzasz UnmodifiableList
opakowanie i kilka groszy. Ostatecznie oszczędności w HashSet
ekwiwalencie są bardziej przekonujące.
Czas zakończenia: użyj, List.of
gdy chcesz mieć listę, która się nie zmienia i Arrays.asList
kiedy chcesz, aby lista mogła się zmieniać (jak pokazano powyżej).