Jak skopiować java.util.List do innej java.util.List

140

Mam, List<SomeBean>który jest wypełniany z usługi sieci Web. Chcę skopiować / sklonować zawartość tej listy do pustej listy tego samego typu. Wyszukiwanie w Google dotyczące kopiowania listy zasugerowało mi użycie Collections.copy()metody. We wszystkich przykładach, które widziałem, lista docelowa miała zawierać dokładną liczbę elementów do skopiowania.

Ponieważ lista, której używam, jest wypełniana za pośrednictwem usługi internetowej i zawiera setki obiektów, nie mogę użyć powyższej techniki. Albo źle go używam ?? !! W każdym razie, aby to zadziałało, próbowałem zrobić coś takiego, ale nadal mam plik IndexOutOfBoundsException.

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

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

Próbowałem użyć, wsListCopy=wsList.subList(0, wsList.size())ale dostałem ConcurrentAccessExceptionpóźniej w kodzie. Uderzenie i próba. :)

W każdym razie moje pytanie jest proste, jak mogę skopiować całą zawartość mojej listy do innej listy? Oczywiście nie poprzez iterację.

Mono Jamoon
źródło
11
Każda kopia będzie oczywiście używać iteracji. Możesz go ukryć, ale nadal tam będzie.
Peter Lawrey,
1
Po pierwsze: czy na pewno musisz skopiować tę listę? Jaka jest Twoja motywacja do zrobienia tego?
ppeterka
2
Tak, iteracja jest po prostu ukryta pod tymi warstwami. Ale komentarz został dodany do, aby zapobiec powtarzaniu odpowiedzi. :)
Mono Jamoon
@ppeterka Wykonuję operacje na liście, takie jak removeAll (). Powoduje to utratę oryginalnych danych przez listę. „Te dane” są również wymagane później.
Mono Jamoon
Jaki jest rzeczywisty typ listy, przez którą powraca app.allInOne(template)? ArrayList?
Andremoniy

Odpowiedzi:

240

Po prostu użyj tego:

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

Uwaga: nadal nie jest bezpieczny wątkowo, jeśli modyfikujesz otherListz innego wątku, możesz chcieć zrobić to otherList(a nawet newList) CopyOnWriteArrayListna przykład - lub użyć prymitywu blokady, takiego jak ReentrantReadWriteLock, aby serializować dostęp do odczytu / zapisu do dowolnych list jednocześnie dostępne.

fge
źródło
1
Teraz po prostu czuję się naprawdę głupio :) Mam nadzieję, że skonstruowanie go w ten sposób nie rzuci żadnego ConcurrentAccessException.
Mono Jamoon
5
+1 jeśli otrzyma ConcurrentModifcationException, ma problem z współbieżnością, który musi najpierw naprawić.
Peter Lawrey,
6
Dlaczego ta odpowiedź ma tyle punktów, jeśli pytanie dotyczyło „kopiuj / klonuj”? To, o ile inne odpowiedzi nie mają nic wspólnego z klonowaniem. Te same odwołania zostaną zachowane dla obiektów w kolekcjach niezależnie od używanych metod narzędziowych specyficznych dla kolekcji / strumienia.
yuranos
3
Odpowiedź jest zła. Treść nie jest kopiowana. Tylko to odniesienia.
Niesamowity styczeń
34

To naprawdę fajny sposób na zrobienie tego w Javie 8:

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

Oczywiście zaletą jest to, że możesz filtrować i przeskakiwać tylko do kopii części listy.

na przykład

//don't copy the first element 
List<String> list2 = list1.stream().skip(1).collect(Collectors.toList());
Dan
źródło
4
Czy wynikowa lista jest głęboką czy płytką kopią oryginalnej listy?
Ad Infinitum
7
Płytka kopia.
kap
3
To niestety również nie jest bezpieczne dla wątków. Zakładając, że listzostanie zmieniony, gdy kolektor jest uruchomiony, ConcurrentModificationExceptionrzuca się a.
C-Otto
@Dan, jak pominąć kopiowanie ostatniego elementu?
CKM
@chandresh, aby pominąć kopiowanie ostatniego elementu, po prostu użyjesz.limit(list1.size() - 1)
Matthew Carpenter
14
originalArrayList.addAll(copyArrayofList);

Pamiętaj, że za każdym razem, gdy używasz metody addAll () do kopiowania, zawartość obu list tablic (originalArrayList i copyArrayofList) odniesień do tych samych obiektów zostanie dodana do listy, więc jeśli zmodyfikujesz którykolwiek z nich, copyArrayofList również odzwierciedlają tę samą zmianę.

Jeśli nie chcesz efektu ubocznego, musisz skopiować każdy element z originalArrayList do copyArrayofList, tak jak przy użyciu pętli for lub while.

Divyesh Kanzariya
źródło
2
Jest to jedna z niewielu prawdziwych odpowiedzi tutaj, ponieważ określa #addAll tworzy płytką kopię, a także jak kopiować głęboko. Więcej szczegółów: stackoverflow.com/questions/715650/ ...
cellepo
7

Próbowałem zrobić coś takiego, ale nadal mam wyjątek IndexOutOfBoundsException.

Otrzymałem ConcurrentAccessException

Oznacza to, że modyfikujesz listę podczas próby jej skopiowania, najprawdopodobniej w innym wątku. Aby to naprawić, musisz albo

  • użyj kolekcji, która jest przeznaczona do jednoczesnego dostępu.

  • odpowiednio zablokuj kolekcję, abyś mógł ją iterować (lub pozwól wywołać metodę, która zrobi to za Ciebie)

  • znajdź miejsce, aby uniknąć konieczności kopiowania oryginalnej listy.

Peter Lawrey
źródło
4

Począwszy od Java 10 :

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

List.copyOf()zwraca niemodyfikowalny Listzawierający elementy danego Collection.

Podane Collectionnie może być nulli nie może zawierać żadnych nullelementów.

Ponadto, jeśli chcesz stworzyć głęboki kopii a List, można znaleźć wiele dobrych odpowiedzi tutaj .

Oleksandr Pyrohov
źródło
3

W Javie 8 jest jeszcze jedna metoda, która zapewnia zerową ochronę.

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

Jeśli chcesz pominąć jeden element.

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

W przypadku języka Java 9+ można użyć metody strumieniowej Optional

Optional.ofNullable(wsList)
    .stream()
    .flatMap(Collection::stream)
    .collect(Collectors.toList())
Nicolas Henneaux
źródło
1

Miałem ten sam problem ConcurrentAccessException i moim rozwiązaniem było:

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

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

Działa więc tylko jedną operację w tym samym czasie i pozwala uniknąć wyjątku ...

T04435
źródło
1

Próbowałem czegoś podobnego i udało mi się odtworzyć problem (IndexOutOfBoundsException). Poniżej moje ustalenia:

1) Implementacja Collections.copy (destList, sourceList) najpierw sprawdza rozmiar listy docelowej, wywołując metodę size (). Ponieważ wywołanie metody size () zawsze zwróci liczbę elementów na liście (w tym przypadku 0), konstruktor ArrayList (capacity) zapewnia tylko początkową pojemność tablicy zapasowej i nie ma to żadnego związku z wielkość listy. Dlatego zawsze otrzymujemy wyjątek IndexOutOfBoundsException.

2) Stosunkowo prostym sposobem jest użycie konstruktora, który jako argument przyjmuje kolekcję:

List<SomeBean> wsListCopy=new ArrayList<SomeBean>(wsList);  
Abhay Yadav
źródło
1

Możesz użyć addAll ().

np .: wsListCopy.addAll(wsList);

samaludheen cignes
źródło
0

re indexOutOfBoundsException:, twoje argumenty podlisty są problemem; musisz zakończyć podlistę na rozmiarze-1. Będąc od zera, ostatni element listy ma zawsze rozmiar 1, nie ma elementu w pozycji rozmiaru, stąd błąd.

Jon Nelson
źródło
0

Nie widzę poprawnej odpowiedzi. Jeśli chcesz uzyskać głęboką kopię, musisz ręcznie iterować i skopiować obiekt (możesz użyć konstruktora kopiującego).

Niesamowity Jan
źródło
To jedna z niewielu prawdziwych odpowiedzi tutaj. Więcej szczegółów: stackoverflow.com/questions/715650/…
cellepo
-2

Jeśli nie chcesz, aby zmiany na jednej liście wpływały na inną listę, spróbuj tego. Pomogło.
Mam nadzieję, że to pomoże.

  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
źródło
-3

Funkcja subList to sztuczka, zwracany obiekt wciąż znajduje się na oryginalnej liście. więc jeśli wykonasz jakąkolwiek operację w subList, spowoduje to współbieżny wyjątek w kodzie, bez względu na to, czy jest to pojedynczy wątek, czy wiele wątków.

weixingsun
źródło