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ę.


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.


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

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.


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.


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 .


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

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 ...


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


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.



-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]

-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.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.