Utworzyć zmienną listę z tablicy?

85

Mam tablicę, którą chciałbym zamienić na a List, aby zmodyfikować zawartość tablicy.

Przepełnienie stosu ma mnóstwo pytań / odpowiedzi, adres Arrays.asList()i jak tylko zapewnia widok na liście podstawowej tablicy, a jak próbuje manipulować wynikowej liście będzie ogólnie rzucić UnsupportedOperationExceptionjako metod stosowanych do manipulowania listy (np add(), remove()etc.) są nie zaimplementowane przez implementację listy dostarczoną przez Arrays.asList().

Ale nie mogę znaleźć przykładu, jak zamienić tablicę w zmienną listę. Przypuszczam, że mogę przechodzić przez tablicę i put()każdą wartość do nowej listy, ale zastanawiam się, czy istnieje interfejs, który może to zrobić za mnie.

ericsoco
źródło

Odpowiedzi:

122

Jeden prosty sposób:

Foo[] array = ...;
List<Foo> list = new ArrayList<Foo>(Arrays.asList(array));

Stworzy to zmienną listę - ale będzie to kopia oryginalnej tablicy. Zmiana listy nie spowoduje zmiany tablicy. Możesz oczywiście skopiować go później, używająctoArray .

Jeśli chcesz utworzyć zmienny widok na tablicy, uważam, że będziesz musiał to zaimplementować samodzielnie.

Jon Skeet
źródło
2
Arrays.asList zwraca widok na tablicę, z tymi obsługiwanymi metodami mutacji, które nie wpływają na rozmiar listy
Timo Westkämper,
1
@ jon-skeet Wiem, właśnie stwierdziłem, że Arrays.asList daje listę obsługiwaną przez tablicę z ograniczoną zmiennością, jeśli potrzebujesz dodać / usunąć / wstawić, to opakowanie ArrayList jest lepszym podejściem.
Timo Westkämper,
4
Java musi jasno określić zmienność / niezmienność we wszystkich tych statycznych metodach fabrycznych. Trudno jest dowiedzieć się, że wykonałeś niezmienną rzecz w czasie wykonywania.
dustinevan
1
@dustinevan: Dokumentacja jest całkiem przejrzysta. IMO: „Zwraca listę o stałym rozmiarze wspartą podaną tablicą. (Zmiany w zwróconej liście„ zapisuj ”do tablicy.)”
Jon Skeet
1
@JonSkeet nie chce tracić czasu - dzięki za wszystko, co robisz. Chciałbym tylko zagłosować za większą przejrzystością samych nazw - jestem pewien, że dokumenty są jasne. Niektórzy z nas tańczą między językami, co jest dość oczywiste w innych językach.
dustinevan
23

A jeśli używasz Google Collection API (Guava):

Lists.newArrayList(myArray);
vsingh
źródło
1
To jest najbardziej zwięzła odpowiedź. Dzięki.
eugene82
2
Nawet sama Guava zaleca użycie jednego z nich new ArrayList<>(Arrays.asList(...))- javadoc dla tej metody sugeruje, że stanie się ona przestarzała, ponieważ nie jest wystarczająco przydatna.
Logan Pickup
1
2020 i nadal nie jest przestarzałe. Wskakuj!
markthegrea
13

Ten prosty kod wykorzystujący Stream API zawarty w Javie 8 tworzy zmienną listę (lub widok) zawierającą elementy twojej tablicy:

Foo[] array = ...;
List<Foo> list = Stream.of(array).collect(Collectors.toCollection(ArrayList::new));

Lub równie ważne:

List<Foo> list = Arrays.stream(array).collect(Collectors.toCollection(ArrayList::new));
Mikael F.
źródło
4

Jeśli używasz kolekcji Eclipse (dawniej GS Kolekcje ), możesz użyć FastList.newListWith(...)lubFastList.wrapCopy(...) .

Obie metody pobierają varargs, więc możesz utworzyć tablicę w linii lub przekazać w istniejącej tablicy.

MutableList<Integer> list1 = FastList.newListWith(1, 2, 3, 4);

Integer[] array2 = {1, 2, 3, 4};
MutableList<Integer> list2 = FastList.newListWith(array2);

Różnica między tymi dwiema metodami polega na tym, czy tablica zostanie skopiowana. newListWith()nie kopiuje tablicy i dlatego zajmuje stały czas. Powinieneś unikać jego używania, jeśli wiesz, że tablica może zostać zmutowana w innym miejscu.

Integer[] array2 = {1, 2, 3, 4};
MutableList<Integer> list2 = FastList.newListWith(array2);
array2[1] = 5;
Assert.assertEquals(FastList.newListWith(1, 5, 3, 4), list2);

Integer[] array3 = {1, 2, 3, 4};
MutableList<Integer> list3 = FastList.wrapCopy(array3);
array3[1] = 5;
Assert.assertEquals(FastList.newListWith(1, 2, 3, 4), list3);

Uwaga: jestem promotorem Eclipse Collections.

Craig P. Motlin
źródło
1
To fajne API kolekcji, które tam masz. Pierwszą, którą widziałem, która może mnie skusić do odejścia od własnych implementacji ... jedyną rzeczą, której wydaje mi się brakować, a która wydaje mi się ogólnie użyteczna, jest posortowana implementacja zestawu wspierana przez tablicę (która, moim zdaniem, jest znacznie bardziej wydajna niż implementacja oparta na drzewie dla danych, które są rzadko modyfikowane, lub dla zbiorów, które mogą być często modyfikowane, ale zazwyczaj zawierają mniej niż 10 elementów).
Jules
0
myNewArrayList = new ArrayList<>(Arrays.asList(myArray));
Sid
źródło
1
@JonSkeet Wiem, że twój komentarz pochodzi z 2012 r. I żyję teraz w przyszłości, ale zakładam, że ten komentarz nie był dobry, biorąc pod uwagę, że moje IDE specjalnie podkreśla i mówi „hej, nie deklaruj tego za pomocą zadeklarowany typ. nie potrzebujesz go tam "?
Brent Thoenen
1
@BrentThoenen: Nie rozumiem twojego komentarza. Czy zauważyłeś, że mój komentarz dotyczył rewizji 1, w której użyto myNewArrayList = new ArrayList(...), tj. Typu surowego? Istnieje różnica między „użyciem operatora diamentu, aby kompilator opracował argument typu”, a „użyciem surowego typu”.
Jon Skeet
1
Opublikowałem tę odpowiedź i żyłem w zapomnieniu przez cały ten czas, że @JonSkeet sam skomentował moją odpowiedź. Dzięki Brent za komentarz.
Sid
@JonSkeet ahh, moja wina. nie sprawdziłem wersji, którą komentujesz. Zrobiłem błędne założenie, ponieważ java z 2012 roku przyjęła pusty operator diamentu również jako typ surowy. To jest moje b. Dziękuję za odpowiedź!
Brent Thoenen
0

Dodanie kolejnej opcji za pomocą Streams API:

List<Foo> list = Arrays.stream(array).collect(Collectors.toList());
Sahil Chhabra
źródło
2
Problem z rozwiązaniem polega na tym, że Collectors # toList nie ma gwarancji zmienności , a zatem nie spełnia wymagań.
MikaelF