So kopieren Sie eine java.util.List in eine andere java.util.List

135

Ich habe eine List<SomeBean>, die von einem Webdienst ausgefüllt wird. Ich möchte den Inhalt dieser Liste in eine leere Liste des gleichen Typs kopieren / klonen. Eine Google-Suche zum Kopieren einer Liste schlug mir vor, die Collections.copy()Methode zu verwenden . In allen Beispielen, die ich gesehen habe, sollte die Zielliste die genaue Anzahl der Elemente enthalten, für die das Kopieren stattfinden soll.

Da die von mir verwendete Liste über einen Webdienst ausgefüllt ist und Hunderte von Objekten enthält, kann ich die oben beschriebene Technik nicht verwenden. Oder ich benutze es falsch ?? !! Wie auch immer, damit es funktioniert, habe ich versucht, so etwas zu tun, aber ich habe immer noch eine IndexOutOfBoundsException.

List<SomeBean> wsList = app.allInOne(template);

List<SomeBean> wsListCopy=new ArrayList<SomeBean>(wsList.size());   
Collections.copy(wsListCopy,wsList);
System.out.println(wsListCopy.size());

Ich habe versucht, das zu verwenden, wsListCopy=wsList.subList(0, wsList.size())aber ich habe ConcurrentAccessExceptionspäter im Code eine. Hit und Versuch. :) :)

Wie auch immer, meine Frage ist einfach: Wie kann ich den gesamten Inhalt meiner Liste in eine andere Liste kopieren? Natürlich nicht durch Iteration.

Mono Jamoon
quelle
11
Jede Kopie verwendet natürlich eine Iteration. Sie können es verstecken, aber es wird immer noch da sein.
Peter Lawrey
1
Zunächst einmal: Sind Sie sicher, dass Sie diese Liste kopieren müssen? Was ist Ihre Motivation dafür?
ppeterka
2
Ja, die Iteration ist nur unter diesen Ebenen verborgen. Der Kommentar wurde jedoch hinzugefügt, um Iterationsantworten zu verhindern. :)
Mono Jamoon
@ppeterka Ich führe Operationen an der Liste aus, wie removeAll (). Dies führt dazu, dass die Liste ihre ursprünglichen Daten verliert. Und "diese Daten" werden auch danach benötigt.
Mono Jamoon
Was ist der tatsächliche Typ einer Liste, die zurückgegeben wird app.allInOne(template)? ArrayList?
Andremoniy

Antworten:

235

Verwenden Sie einfach dies:

List<SomeBean> newList = new ArrayList<SomeBean>(otherList);

Hinweis: Wenn Sie otherListvon einem anderen Thread aus ändern, ist dies immer noch nicht threadsicher. Möglicherweise möchten Sie dies otherList(und sogar newList) CopyOnWriteArrayListzum Beispiel festlegen - oder ein Sperrprimitiv wie ReentrantReadWriteLock verwenden, um den Lese- / Schreibzugriff auf beliebige Listen zu serialisieren gleichzeitig zugegriffen.

fge
quelle
1
Jetzt fühle ich mich einfach wirklich dumm :) Ich hoffe, dass das Konstruieren so nichts bringt ConcurrentAccessException.
Mono Jamoon
5
+1 Wenn er ConcurrentModifcationException erhält, hat er ein Parallelitätsproblem, das er zuerst beheben muss.
Peter Lawrey
5
Warum bekommt diese Antwort so viele Punkte, wenn die Frage "Kopieren / Klonen" erwähnt? Dies, solange einige andere Antworten nichts mit dem Klonen zu tun haben. Die gleichen Referenzen werden für die Objekte in den Sammlungen beibehalten, unabhängig davon, welche sammlungs- / streamspezifischen Dienstprogrammmethoden Sie verwenden.
Yuranos
3
Die Antwort ist falsch. Der Inhalt wird nicht kopiert. Nur es sind Referenzen.
Der unglaubliche
33

Dies ist eine wirklich schöne Java 8-Methode:

List<String> list2 = list1.stream().collect(Collectors.toList());

Der Vorteil hierbei ist natürlich, dass Sie nur einen Teil der Liste filtern und überspringen können.

z.B

//don't copy the first element 
List<String> list2 = list1.stream().skip(1).collect(Collectors.toList());
Dan
quelle
4
Ist die resultierende Liste eine tiefe oder flache Kopie der ursprünglichen Liste?
Ad Infinitum
7
Eine flache Kopie.
Kap
3
Dies ist leider auch nicht threadsicher. Angenommen, listwird geändert, während der Kollektor läuft, ConcurrentModificationExceptionwird a geworfen.
C-Otto
@ Dan, Wie überspringe ich das Kopieren des letzten Elements?
CKM
@chandresh, um das Kopieren des letzten Elements zu überspringen, würden Sie nur verwenden.limit(list1.size() - 1)
Matthew Carpenter
13
originalArrayList.addAll(copyArrayofList);

Beachten Sie bitte, dass bei Verwendung der addAll () -Methode zum Kopieren der Inhalt der beiden Array-Listen (originalArrayList und copyArrayofList), die auf dieselben Objekte verweisen, zur Liste hinzugefügt wird. Wenn Sie also eines dieser Objekte ändern, wird auch copyArrayofList geändert spiegeln die gleiche Veränderung wider.

Wenn Sie keinen Nebeneffekt wünschen, müssen Sie jedes Element aus der ursprünglichenArrayList in die copyArrayofList kopieren, z. B. mithilfe einer for- oder while-Schleife.

Divyesh Kanzariya
quelle
2
Dies ist eine der wenigen echten Antworten hier, da hier angegeben ist, dass #addAll eine flache Kopie erstellt und wie eine tiefe Kopie erstellt wird. Weitere Details: stackoverflow.com/questions/715650/…
cellepo
7

Ich habe versucht, so etwas zu tun, aber ich habe immer noch eine IndexOutOfBoundsException.

Ich habe eine ConcurrentAccessException erhalten

Dies bedeutet, dass Sie die Liste ändern, während Sie versuchen, sie zu kopieren, höchstwahrscheinlich in einem anderen Thread. Um dies zu beheben, müssen Sie entweder

  • Verwenden Sie eine Sammlung, die für den gleichzeitigen Zugriff ausgelegt ist.

  • Sperren Sie die Sammlung entsprechend, damit Sie sie durchlaufen können (oder Sie können eine Methode aufrufen, die dies für Sie erledigt).

  • Suchen Sie eine Abwesenheit, um zu vermeiden, dass Sie die ursprüngliche Liste kopieren müssen.

Peter Lawrey
quelle
4

Ab Java 10 :

List<E> oldList = List.of();
List<E> newList = List.copyOf(oldList);

List.copyOf()Gibt eine nicht veränderbare Datei zurück, Listdie die Elemente der angegebenen enthält Collection.

Das Gegebene Collectiondarf nicht sein nullund darf keine nullElemente enthalten .

Auch, wenn Sie eine tiefe Kopie eines erstellen möchten List, können Sie viele gute Antworten finden hier .

Oleksandr Pyrohov
quelle
3

Es gibt eine andere Methode mit Java 8 auf null-sichere Weise.

List<SomeBean> wsListCopy = Optional.ofNullable(wsList)
                                    .map(List::stream)
                                    .orElseGet(Stream::empty)
                                    .collect(Collectors.toList());

Wenn Sie ein Element überspringen möchten.

List<SomeBean> wsListCopy = Optional.ofNullable(wsList)
                                    .map(List::stream)
                                    .orElseGet(Stream::empty)
                                    .skip(1)
                                    .collect(Collectors.toList());
Nicolas Henneaux
quelle
1

Ich hatte das gleiche Problem ConcurrentAccessException und mysolution war:

List<SomeBean> tempList = new ArrayList<>();

for (CartItem item : prodList) {
  tempList.add(item);
}
prodList.clear();
prodList = new ArrayList<>(tempList);

Es funktioniert also immer nur eine Operation und vermeidet die Ausnahme ...

T04435
quelle
1

Ich habe etwas Ähnliches versucht und konnte das Problem reproduzieren (IndexOutOfBoundsException). Unten sind meine Ergebnisse:

1) Die Implementierung der Collections.copy (destList, sourceList) überprüft zunächst die Größe der Zielliste durch Aufrufen der size () -Methode. Da der Aufruf der size () -Methode immer die Anzahl der Elemente in der Liste zurückgibt (in diesem Fall 0), stellt der Konstruktor ArrayList (Kapazität) nur die Anfangskapazität des Hintergrundarrays sicher, und dies hat keine Beziehung zu Größe der Liste. Daher erhalten wir immer IndexOutOfBoundsException.

2) Eine relativ einfache Möglichkeit besteht darin, den Konstruktor zu verwenden, der eine Sammlung als Argument verwendet:

List<SomeBean> wsListCopy=new ArrayList<SomeBean>(wsList);  
Abhay Yadav
quelle
0

re : indexOutOfBoundsException, Ihre Unterlistenargumente sind das Problem; Sie müssen die Unterliste bei Größe 1 beenden. Da das letzte Element einer Liste auf Null basiert, ist es immer Größe 1, es befindet sich kein Element an der Größenposition, daher der Fehler.

Jon Nelson
quelle
0

Sie können addAll () verwenden.

z.B : wsListCopy.addAll(wsList);

Samaludheen Cignes
quelle
0

Ich kann keine richtige Antwort sehen. Wenn Sie eine tiefe Kopie wünschen, müssen Sie das Objekt manuell iterieren und kopieren (Sie können einen Kopierkonstruktor verwenden).

Der unglaubliche Jan.
quelle
Dies ist eine der wenigen wahren Antworten hier. Weitere Details: stackoverflow.com/questions/715650/…
cellepo
-2

Wenn Sie nicht möchten, dass Änderungen in einer Liste eine andere Liste bewirken, versuchen Sie dies. Es hat bei mir funktioniert. Ich
hoffe, das hilft.

  public class MainClass {
  public static void main(String[] a) {

    List list = new ArrayList();
    list.add("A");

    List list2 = ((List) ((ArrayList) list).clone());

    System.out.println(list);
    System.out.println(list2);

    list.clear();

    System.out.println(list);
    System.out.println(list2);
  }
}

> Output:   
[A]  
[A]  
[]  
[A]
Aashis Shrestha
quelle
-3

Die Funktion subList ist ein Trick. Das zurückgegebene Objekt befindet sich noch in der ursprünglichen Liste. Wenn Sie also eine Operation in der Unterliste ausführen, wird die gleichzeitige Ausnahme in Ihrem Code verursacht, unabhängig davon, ob es sich um einen einzelnen Thread oder einen Multi-Thread handelt.

weixingsun
quelle