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.asListnie 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.ofi wszystkie kolekcje od wersji Java 1.5 nie pozwalają nulljako element. Próba przekazania nulljako elementu lub nawet wyszukiwania spowoduje utworzenie pliku NullPointerException.
Ponieważ Arrays.asListjest to kolekcja z wersji 1.2 (struktura kolekcji), umożliwia nulls.
listOf.contains(null); // NullPointerException
unmodif.contains(null); // allowed
asList.contains(null); // allowed
Formularz serializowany
Ponieważ List.ofzostał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.asListwywołania wewnętrzne new ArrayList, co gwarantuje nierówność odniesień.
List.ofzależ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.ofwynosi 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.ofimplementacji, 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.ofjest 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 UnmodifiableListopakowanie i kilka groszy. Ostatecznie oszczędności w HashSetekwiwalencie są bardziej przekonujące.
Czas zakończenia: użyj, List.ofgdy chcesz mieć listę, która się nie zmienia i Arrays.asListkiedy chcesz, aby lista mogła się zmieniać (jak pokazano powyżej).