Veränderbare Liste aus Array erstellen?

84

Ich habe ein Array, das ich in ein Array verwandeln möchte List, um den Inhalt des Arrays zu ändern.

Stack - Überlauf hat viele Fragen / Antworten , die Adresse Arrays.asList()und wie es nur eine Listenansicht des zugrunde liegenden Array bietet, und wie versucht wird, die sich ergebende Liste zu manipulieren , wird in der Regel ein Wurf UnsupportedOperationExceptionals Methoden verwendet , um die Liste zu bearbeiten (zB add(), remove()usw.) nicht implementiert durch die List-Implementierung bereitgestellt von Arrays.asList().

Ich kann jedoch kein Beispiel dafür finden, wie ein Array in eine veränderbare Liste umgewandelt werden kann. Ich nehme an, ich kann das Array und put()jeden Wert in einer neuen Liste durchlaufen , aber ich frage mich, ob es eine Schnittstelle gibt, die dies für mich erledigt.

ericsoco
quelle

Antworten:

122

Ein einfacher Weg:

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

Dadurch wird eine veränderbare Liste erstellt - es handelt sich jedoch um eine Kopie des ursprünglichen Arrays. Durch Ändern der Liste wird das Array nicht geändert. Sie können es natürlich später wieder kopieren, indem Sie toArray.

Wenn Sie eine veränderbare Ansicht für ein Array erstellen möchten , müssen Sie dies meiner Meinung nach selbst implementieren.

Jon Skeet
quelle
2
Arrays.asList gibt eine Ansicht auf ein Array zurück, wobei die Mutationsmethoden unterstützt werden, die die Größe der Liste nicht beeinflussen
Timo Westkämper
1
@ jon-skeet Ich weiß, ich habe nur gesagt, dass Arrays.asList Ihnen eine Array-gestützte Liste mit eingeschränkter Veränderlichkeit bietet. Wenn Sie hinzufügen / entfernen / einfügen müssen, ist der ArrayList-Wrapping ein besserer Ansatz.
Timo Westkämper
4
Java muss in all diesen statischen Factory-Methoden die Veränderbarkeit / Unveränderlichkeit deutlich machen. Es ist ein Mist herauszufinden, dass Sie zur Laufzeit eine unveränderliche Sache gemacht haben.
Dustinevan
1
@dustinevan: Die Dokumentation ist ziemlich klar IMO: "Gibt eine Liste mit fester Größe zurück, die von dem angegebenen Array unterstützt wird. (Änderungen an der zurückgegebenen Liste" durchschreiben "in das Array.)"
Jon Skeet
1
@ JonSkeet möchte Ihre Zeit nicht verschwenden - danke für alles, was Sie tun. Ich möchte nur für mehr Klarheit in den Namen selbst abstimmen - ich bin sicher, dass die Dokumente klar sind. Einige von uns tanzen zwischen Sprachen, und dies ist in anderen Sprachen ziemlich klar.
Dustinevan
21

Und wenn Sie Google Collection-APIs verwenden

Lists.newArrayList(myArray)
vsingh
quelle
1
Dies ist die prägnanteste Antwort. Vielen Dank.
Eugen82 vom
2
Sogar Guava selbst empfiehlt die Verwendung von beidem new ArrayList<>(Arrays.asList(...))- das Javadoc für die Methode impliziert, dass es veraltet ist, weil es nicht nützlich genug ist.
Logan Pickup
2020 und immer noch nicht veraltet. Spring rein!
März
11

Dieser einfache Code unter Verwendung der in Java 8 enthaltenen Stream-API erstellt eine veränderbare Liste (oder Ansicht), die die Elemente Ihres Arrays enthält:

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

Oder ebenso gültig:

List<Foo> list = Arrays.stream(array).collect(Collectors.toCollection(ArrayList::new));
MikaelF
quelle
4

Wenn Sie Eclipse-Sammlungen (früher GS-Sammlungen ) verwenden, können Sie FastList.newListWith(...)oder verwenden FastList.wrapCopy(...).

Beide Methoden verwenden varargs, sodass Sie das Array inline erstellen oder ein vorhandenes Array übergeben können.

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

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

Der Unterschied zwischen den beiden Methoden besteht darin, ob das Array kopiert wird oder nicht. newListWith()kopiert das Array nicht und benötigt daher konstante Zeit. Sie sollten es vermeiden, wenn Sie wissen, dass das Array an anderer Stelle mutiert sein könnte.

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);

Hinweis: Ich bin ein Committer für Eclipse-Sammlungen.

Craig P. Motlin
quelle
1
Das ist eine schöne Sammlungs-API, die Sie dort haben. Die erste, die ich gesehen habe, die mich von meinen eigenen Implementierungen ablenken könnte ... Das einzige, was mir anscheinend allgemein nützlich erscheint, ist eine sortierte Set-Implementierung, die von einem Array unterstützt wird (was meiner Meinung nach viel effizienter ist als eine baumbasierte Implementierung entweder für Daten, die selten geändert werden, oder für Sätze, die häufig geändert werden können, aber normalerweise weniger als 10 Elemente enthalten.
Jules
0
myNewArrayList = new ArrayList<>(Arrays.asList(myArray));
Sid
quelle
1
@ JonSkeet Ich weiß, dass Ihr Kommentar aus dem Jahr 2012 stammt und ich lebe jetzt in der Zukunft, aber ich gehe davon aus, dass dieser Kommentar nicht gut gehalten hat, wenn man bedenkt, dass meine IDE dies ausdrücklich unterstreicht und sagt: "Hey, deklariere dies nicht mit einem deklarierter Typ. Du brauchst ihn dort nicht "?
Brent Thoenen
1
@BrentThoenen: Ich verstehe deinen Kommentar nicht. Haben Sie bemerkt, dass sich mein Kommentar auf Revision 1 bezog, die myNewArrayList = new ArrayList(...)den Rohtyp verwendete? Es gibt einen Unterschied zwischen "Verwenden des Diamantoperators, damit der Compiler ein Typargument ausarbeiten kann" und "Verwenden eines Rohtyps".
Jon Skeet
1
Ich habe diese Antwort gepostet und die ganze Zeit in Vergessenheit geraten, als @JonSkeet selbst meine Antwort kommentierte. Danke Brent für den Kommentar.
Sid
@ JonSkeet ahh, mein schlechtes. Ich habe die Revision, die Sie kommentiert haben, nicht überprüft. Ich habe eine falsche Annahme gemacht, dass Java 2012 auch einen leeren Diamantoperator als Rohtyp angenommen hat. Das ist mein b. Danke für die Antwort!
Brent Thoenen
0

Hinzufügen einer weiteren Option mithilfe der Streams-API:

List<Foo> list = Arrays.stream(array).collect(Collectors.toList());
Sahil Chhabra
quelle
2
Das Problem bei Ihrer Lösung besteht darin, dass Collectors # toList keine Garantie für die Veränderlichkeit bietet und daher nicht den Anforderungen entspricht.
MikaelF