Як скопіювати java.util.List в інший java.util.List


135

У мене є List<SomeBean>те, що заповнено веб-сервісом. Я хочу скопіювати / клонувати вміст цього списку в порожній список того ж типу. Пошук Google для копіювання списку запропонував мені використовувати Collections.copy()метод. У всіх прикладах, які я бачив, список призначення повинен містити точну кількість елементів для копіювання.

Оскільки список, який я використовую, заповнюється через веб-сервіс, і він містить сотні об'єктів, я не можу використовувати вищевказану техніку. Або я неправильно використовую ?? !! Як би там не було, я намагався зробити щось подібне, але все-таки отримав IndexOutOfBoundsException.

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

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

Я спробував використати, wsListCopy=wsList.subList(0, wsList.size())але ConcurrentAccessExceptionпізніше отримав код. Удар і суд. :)

У будь-якому разі, моє запитання просте, як я можу скопіювати весь вміст свого списку в інший Список? Не через ітерацію, звичайно.


11
Будь-яка копія звичайно використовуватиме ітерацію. Ви можете сховати його, але він все одно буде.
Пітер Лорі

1
Перш за все: ви впевнені, що вам потрібно скопіювати цей список? Яка ваша мотивація в цьому?
ppeterka

2
Так, ітерація просто прихована під цими шарами. Але коментар був доданий для запобігання будь-яких ітераційних відповідей. :)
Mono Jamoon

@ppeterka Я виконую операції зі списку, як-от RemoveAll (). Це призводить до втрати списку вихідних даних. І "ці дані" також потрібні згодом.
Mono Jamoon

Який власне тип списку, який повертається app.allInOne(template)? ArrayList?
Андремоній

Відповіді:


235

Просто скористайтеся цим:

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

Примітка: все-таки не безпечно для потоків, якщо ви змінюєте otherListінший потік, можливо, ви хочете, наприклад, зробити це otherList(і навіть newList) a CopyOnWriteArrayList- або використовувати примітив блокування, наприклад ReentrantReadWriteLock, щоб серіалізувати доступ для читання / запису до будь-яких списків одночасно звертався.


1
Зараз я просто відчуваю себе дурним :) Сподіваюся, що таке конструювання не кине ConcurrentAccessException.
Mono Jamoon


5
+1, якщо він отримує ConcurrentModifcationException, у нього є проблема одночасності, яку потрібно спочатку виправити.
Пітер Лорі

5
Чому ця відповідь набирає стільки балів, якщо у питанні згадується "копіювати / клонувати"? Це, поки деякі інші відповіді не мають нічого спільного з клонуванням. Такі самі посилання зберігатимуться для об'єктів всередині колекції незалежно від методів колекції / потоку, які ви використовуєте.
yuranos

3
Відповідь неправильна. Вміст не копіюється. Тільки це посилання.
Неймовірний січень

33

Це дійсно приємний спосіб Java 8:

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

Звичайно, перевага тут полягає в тому, що ви можете відфільтрувати та перейти лише до копії частини списку.

напр

//don't copy the first element 
List<String> list2 = list1.stream().skip(1).collect(Collectors.toList());

4
Чи є отриманий список глибокою або дрібною копією оригінального списку?
Ad Infinitum

7
Неглибока копія.
кап

3
Це, на жаль, також не є безпечним для ниток. Припущення listзмінюється, коли колектор працює, a ConcurrentModificationExceptionкидається.
C-Otto

@Dan, Як пропустити копіювання останнього елемента?
CKM

@chandresh, щоб пропустити копіювання останнього елемента, ви просто використаєте.limit(list1.size() - 1)
Matthew Carpenter

13
originalArrayList.addAll(copyArrayofList);

Будь ласка, майте на увазі, коли ви використовуєте метод addAll () для копіювання, вміст обох списків масивів (originalArrayList та copyArrayofList) посилань на ті самі об’єкти буде додано до списку, тому якщо ви модифікуєте будь-який з них, то copyArrayofList також також буде відображають ті ж зміни.

Якщо ви не хочете побічного ефекту, вам потрібно скопіювати кожен елемент з originalArrayList в copyArrayofList, наприклад, використовуючи цикл for або while.


2
Це один з небагатьох правдивих відповідей тут, оскільки він вказує #addAll робить дрібну копію, а також спосіб глибокої копіювання. Детальніше: stackoverflow.com/questions/715650 / ...
cellepo

7

Я намагався зробити щось подібне, але все ж отримав IndexOutOfBoundsException.

Я отримав ConcurrentAccessException

Це означає, що ви змінюєте список, намагаючись скопіювати його, швидше за все, в інший потік. Щоб виправити це, вам доведеться будь-яке

  • використовувати колекцію, розроблену для одночасного доступу.

  • заблокувати колекцію належним чином, щоб ви могли повторити її (або дозволити викликати метод, який робить це для вас)

  • знайдіть подалі, щоб не копіювати оригінальний список.


4

Починаючи з Java 10 :

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

List.copyOf()повертає немодифікується, Listщо містить елементи заданого Collection.

Дане Collectionне повинно бути null, і воно не повинно містити ніяких nullелементів.

Крім того , якщо ви хочете , щоб створити глибоку копію List, ви можете знайти багато хороших відповідей тут .


3

Є інший метод з Java 8 безпечним для нуля способом.

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

Якщо ви хочете пропустити один елемент.

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

З Java 9+ може використовуватися потоковий метод Необов’язковий

Optional.ofNullable(wsList)
    .stream()
    .flatMap(Collection::stream)
    .collect(Collectors.toList())

1

У мене була та ж проблема ConcurrentAccessException і mysolution повинен був:

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

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

Таким чином, це працює лише одна операція на той час і уникає Виходу ...


1

Я спробував щось подібне і зміг відтворити проблему (IndexOutOfBoundsException). Нижче наведені мої висновки:

1) Реалізація Collections.copy (destList, sourceList) спочатку перевіряє розмір списку призначення, викликаючи метод size (). Оскільки виклик методу size () завжди буде повертати кількість елементів у списку (0 у цьому випадку), конструктор ArrayList (місткість) забезпечує лише початкову ємність резервного масиву, і це не має жодного відношення до розмір списку. Отже, ми завжди отримуємо IndexOutOfBoundsException.

2) Порівняно простий спосіб - використовувати конструктор, який приймає колекцію як аргумент:

List<SomeBean> wsListCopy=new ArrayList<SomeBean>(wsList);  

0

re:, indexOutOfBoundsExceptionваші аргументи підпису - проблема; вам потрібно закінчити підпис із розміром-1. Будучи на основі нуля, останній елемент списку завжди має розмір-1, в позиції розміру немає елемента, отже, помилка.



0

Я не бачу правильної відповіді. Якщо ви хочете отримати глибоку копію, вам слід повторити і скопіювати об’єкт вручну (ви можете використовувати конструктор копій).


Це один з небагатьох правдивих відповідей тут. Детальніше: stackoverflow.com/questions/715650 / ...
cellepo

-2

Якщо ви не хочете, щоб зміни в одному списку впливали на інший список, спробуйте це. Я працював для мене.
Сподіваюся, це допоможе.

  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

функція subList - хитрість, повернутий об'єкт все ще знаходиться у вихідному списку. тому якщо ви виконаєте будь-яку операцію в subList, це призведе до паралельного виключення у вашому коді, незалежно від того, це однопоточний або багатопотоковий.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.