Java 9 wprowadziła nowe metody fabryczne dla list List.of
:
List<String> strings = List.of("first", "second");
Jaka jest różnica między poprzednią a nową opcją? To znaczy, jaka jest różnica między tym:
Arrays.asList(1, 2, 3);
i to:
List.of(1, 2, 3);
Odpowiedzi:
Arrays.asList
zwraca zmienną listę, podczas gdy lista zwrócona przezList.of
jest niezmienna :Arrays.asList
dopuszcza elementy puste, podczas gdyList.of
nie:contains
zachowuje się inaczej w przypadku wartości null:Arrays.asList
zwraca widok przekazanej tablicy, więc zmiany w tablicy zostaną również odzwierciedlone na liście. DoList.of
tego nie jest prawdą:źródło
List.contains(Object o)
javadoc 's : "Zgłasza [...] NullPointerException - jeśli określony element ma wartość null i ta lista nie zezwala na elementy puste (opcjonalne)". Lub z obszernego wprowadzenia do interfejsu, o którym niewielu mówi: „Niektóre implementacje kolekcji mają ograniczenia dotyczące elementów, które mogą zawierać”List.of
nie powrócić jakiśImmutableList
typ, jego rzeczywista nazwa to tylko drobny szczegół realizacja niepubliczne. Jeśli była publiczna i ktośList
ponownie ją przesłał, jaka była różnica? Gdzie jest różnicaArrays.asList
, która zwraca niepublicznąList
implementację, która zgłasza wyjątek podczas próbyadd
lubremove
, lub lista zwrócona,Collections.unmodifiableList
która nie pozwala na żadną modyfikację? Chodzi o kontrakty określone wList
interfejsie. Interfejsy kolekcji z opcjonalnymi metodami zawsze były nieczytelnym OOP od Java 1.2…Różnice między
Arrays.asList
iList.of
Zobacz JavaDocs i ten wykład autorstwa Stuarta Marksa (lub jego poprzednich wersji).
Będę używał następujących przykładów kodu:
Niezmienność strukturalna (lub: niemodyfikowalność)
Każda próba zmiany strukturalnej
List.of
spowoduje, że plikUnsupportedOperationException
. 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
.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 przekazanianull
jako elementu lub nawet wyszukiwania spowoduje utworzenie plikuNullPointerException
.Ponieważ
Arrays.asList
jest to kolekcja z wersji 1.2 (struktura kolekcji), umożliwianull
s.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ętrznenew 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ć.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ą.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):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ładsize()
może zwrócić stałą bez pobierania długości tablicy icontains(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) doco tworzy 2 listy plus inne narzuty. Jeśli chodzi o miejsce, oszczędzasz
UnmodifiableList
opakowanie i kilka groszy. Ostatecznie oszczędności wHashSet
ekwiwalencie są bardziej przekonujące.Czas zakończenia: użyj,
List.of
gdy chcesz mieć listę, która się nie zmienia iArrays.asList
kiedy chcesz, aby lista mogła się zmieniać (jak pokazano powyżej).źródło
Arrays.asList
nie jest w pełni zmienny.asList.add(1);
rzucaUnsupportedOperationException
.List.of
czasu, w którym ludzie chcieliby zadzwonićcontains
i nie być zaskoczonym wyjątkiem NullPointerException.Podsumujmy różnice między List.of i Arrays.asList
List.of
może być najlepiej stosowany, gdy zestaw danych jest mniejszy i niezmieniony, natomiastArrays.asList
może być najlepiej używany w przypadku dużego i dynamicznego zestawu danych.List.of
zajmuje bardzo mniej miejsca narzutu, ponieważ ma implementację opartą na polach i zużywa mniej miejsca na sterty, zarówno pod względem stałego narzutu, jak i na podstawie liczby elementów. natomiastArrays.asList
zająć więcej miejsca nad głową, ponieważ podczas inicjalizacji tworzy więcej obiektów w sterty.Kolekcja zwrócona przez
List.of
jest niezmienna i dlatego jest bezpieczna wątkowo, podczas gdy kolekcja zwrócona przezArrays.asList
jest modyfikowalna i nie jest bezpieczna wątkowo. (Niezmienne wystąpienia kolekcji zwykle zużywają znacznie mniej pamięci niż ich zmienne odpowiedniki).List.of
nie zezwala na puste elementy, podczas gdyArrays.asList
zezwala na puste elementy.źródło
Arrays.asList
versusList.of
, biorąc pod uwagę, że to pierwsze jest dosłownie tylko opakowaniem wokół tablicy. Przynajmniej wydaje się, że implementacja OpenJDK ma bardzo mały narzut. W rzeczywistościList.of
musiałby wykonać kopie dowolnej przekazanej tablicy, więc jeśli sama tablica nie będzie wkrótce GC, wydawałoby się, żeList.of
ma znacznie większy ślad pamięci.List.of(x)
iList.of(x, y)
są bardziej wydajne, ponieważ w ogóle nie przydzielają tablicList.of
metody nie są wymagane do zwracania nowych list za każdym razem. Te listy mają nieokreśloną tożsamość, więc na poziomie maszyny JVM może być obsługiwane buforowanie, deduplikacja lub skalaryzacja. Jeśli nie w tej wersji, to może w następnej. Kontrakt na to pozwala. W przeciwieństwie do tego,Array.asList
zależy od tożsamości przekazanej tablicy, ponieważ wynikowa lista jest zmiennym widokiem tablicy, odzwierciedlającym wszystkie zmiany dwukierunkowo.Oprócz powyższych odpowiedzi są pewne operacje na oba
List::of
iArrays::asList
różnią:Więcej o kolekcjach :: singletonList Vs. Lista
źródło