Как скопировать java.util.List в другой java.util.List

У меня есть 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. Удар и испытание. :)

В любом случае, мой вопрос прост: как я могу скопировать все содержимое моего списка в другой список? Конечно, не с помощью итераций.


person Mono Jamoon    schedule 14.01.2013    source источник
comment
Конечно, любая копия будет использовать итерацию. Вы можете спрятать его, но он все равно будет там.   -  person Peter Lawrey    schedule 14.01.2013
comment
Прежде всего: вы уверены, что вам нужно скопировать этот список? Какова ваша мотивация в этом?   -  person ppeterka    schedule 14.01.2013
comment
Да, итерация просто скрыта под этими слоями. Но комментарий был добавлен, чтобы предотвратить повторение ответов. :)   -  person Mono Jamoon    schedule 14.01.2013
comment
@ppeterka Я выполняю операции со списком, например removeAll (). Это приводит к потере исходных данных в списке. И эти данные также потребуются впоследствии.   -  person Mono Jamoon    schedule 14.01.2013
comment
Каков фактический тип списка, который возвращает app.allInOne(template)? ArrayList?   -  person Andremoniy    schedule 14.01.2013
comment
Вам нужна мелкая или глубокая копия?   -  person cellepo    schedule 23.11.2018


Ответы (13)


Просто используйте это:

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

Примечание: по-прежнему не потокобезопасен, если вы изменяете otherList из другого потока, вы можете сделать этот otherList (и даже newList) _ 5_, например, или используйте примитив блокировки, такой как ReentrantReadWriteLock, чтобы сериализовать доступ для чтения / записи к любым спискам, к которым осуществляется одновременный доступ.

person fge    schedule 14.01.2013
comment
Теперь я чувствую себя действительно глупо :) Я надеюсь, что такое построение не вызовет никаких ConcurrentAccessException. - person Mono Jamoon; 14.01.2013
comment
Javadoc: docs.oracle.com/javase/1.4.2/docs/api/java/util/ - person lcguida; 14.01.2013
comment
+1, если он получает ConcurrentModifcationException, у него есть проблема с параллелизмом, которую он должен исправить в первую очередь. - person Peter Lawrey; 14.01.2013
comment
@RickeshJohn нет, если вы не измените otherList из другого потока (вы же не делаете, не так ли?) - person fge; 14.01.2013
comment
@fge Поскольку он также получает исключение IndexOutOfBoundsException, я думаю, что удаление объектов в другом потоке весьма вероятно. - person Peter Lawrey; 14.01.2013
comment
Несколько потоков !!!! Все, что я делаю, это removeAll (anotherDistantList). И я получаю ConcurrentException. - person Mono Jamoon; 14.01.2013
comment
@PeterLawrey, это верно ... Связано с поточно-ориентированной реализацией. - person fge; 14.01.2013
comment
привет, могу я спросить, какова вычислительная стоимость инициализации списка таким образом? - person Evil Washing Machine; 20.02.2015
comment
Еще одна вещь: при этом вы фактически не копируете внутренний список внутри объектов SomeBean. Они все еще указывают на внутренние списки otherList. Так что будьте осторожны, если собираетесь редактировать внутренние списки - person edoardotognoni; 27.02.2015
comment
что, если исходный список не является ArrayList, и вы хотите, чтобы цель имела ту же реализацию, что и источник? - person amphibient; 25.03.2015
comment
@amphibient конкретная реализация вашего List никогда не должна вызывать беспокойства; если это у вас есть проблема с дизайном, которую вы должны решить в первую очередь. - person fge; 25.03.2015
comment
Как работать, если списки двух разных типов? Пример: Список ‹OrderDetails› orderDetails = new ArrayList ‹Item› (Список корзин); ??? - person Shruthi; 07.10.2015
comment
Почему этот ответ набирает так много баллов, если в вопросе упоминается копирование / клонирование? Это, если некоторые другие ответы не имеют ничего общего с клонированием. Те же ссылки будут сохранены для объектов внутри коллекций, независимо от того, какие служебные методы, специфичные для коллекции / потока, вы используете. - person yuranos; 10.10.2016
comment
Ответ неверный. Контент не копируется. Только ссылки. - person The incredible Jan; 27.04.2018
comment
Глубокая копия информации (которую запрашивает этот вопрос): stackoverflow.com/questions/715650/ - person cellepo; 12.08.2018

Это действительно хороший способ сделать это в Java 8:

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

Конечно, преимущество здесь в том, что вы можете фильтровать и пропускать только часть списка.

e.g.

//don't copy the first element 
List<String> list2 = list1.stream().skip(1).collect(Collectors.toList());
person Dan    schedule 10.12.2015
comment
является ли результирующий список полной или неглубокой копией исходного списка? - person Ad Infinitum; 16.08.2016
comment
Мелкая копия. - person kap; 29.11.2016
comment
Это, к сожалению, также не является потокобезопасным. Предполагая, что list изменяется во время работы сборщика, выдается ConcurrentModificationException. - person C-Otto; 13.03.2017
comment
@Dan, как пропустить копирование последнего элемента? - person CKM; 31.05.2017
comment
@chandresh, чтобы пропустить копирование последнего элемента, вы должны просто использовать .limit(list1.size() - 1) - person Matthew Carpenter; 26.06.2018

originalArrayList.addAll(copyArrayofList);

Помните, что всякий раз при использовании метода addAll () для копирования содержимое обоих списков массивов (originalArrayList и copyArrayofList), ссылки на одни и те же объекты, будут добавлены в список, поэтому, если вы измените любой из них из них copyArrayofList также будет отражать то же изменение.

Если вам не нужен побочный эффект, вам нужно скопировать каждый элемент из originalArrayList в copyArrayofList, например, используя цикл for или while. для глубокой копии вы можете использовать нижеприведенный фрагмент кода.

но еще одно, что вам нужно сделать, реализовать интерфейс Cloneable и переопределить метод clone() для класса SomeBean.

public static List<SomeBean> cloneList(List<SomeBean> originalArrayList) {
    List<SomeBean> copyArrayofList = new ArrayList<SomeBean>(list.size());
    for (SomeBean item : list) copyArrayofList.add(item.clone());
    return clone;
}
person Divyesh Kanzariya    schedule 04.04.2016
comment
Это один из немногих истинных ответов здесь, поскольку он указывает, что #addAll создает неглубокую копию, а также способ глубокой копии. Дополнительные сведения: stackoverflow.com/questions/715650/ - person cellepo; 12.08.2018

Я пытался сделать что-то подобное, но все равно получилось исключение IndexOutOfBoundsException.

У меня ConcurrentAccessException

Это означает, что вы изменяете список, пытаясь скопировать его, скорее всего, в другом потоке. Чтобы исправить это, вам нужно либо

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

  • заблокируйте коллекцию соответствующим образом, чтобы вы могли перебирать ее (или позволить вам вызвать метод, который сделает это за вас)

  • найти далеко, чтобы избежать необходимости копировать исходный список.

person Peter Lawrey    schedule 14.01.2013

Начиная с Java 10:

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

_2 _ возвращает неизменяемый List, содержащий элементы данного Collection.

Данный Collection не должен быть null и не должен содержать никаких null элементов.

Кроме того, если вы хотите создать полную копию List, вы можете найти много хороших ответов здесь.

person Oleksandr Pyrohov    schedule 15.04.2018

В 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

Optional.ofNullable(wsList)
    .stream()
    .flatMap(Collection::stream)
    .collect(Collectors.toList())
person Nicolas Henneaux    schedule 14.12.2017

У меня была та же проблема ConcurrentAccessException, и мое решение заключалось в следующем:

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

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

Таким образом, он выполняет только одну операцию за раз и избегает Exeption ...

person T04435    schedule 16.10.2015

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

1) Реализация Collections.copy (destList, sourceList) сначала проверяет размер целевого списка, вызывая метод size (). Поскольку вызов метода size () всегда будет возвращать количество элементов в списке (в данном случае 0), конструктор ArrayList (capacity) обеспечивает только начальную емкость резервного массива, и это не имеет никакого отношения к размер списка. Следовательно, мы всегда получаем исключение IndexOutOfBoundsException.

2) Относительно простой способ - использовать конструктор, который принимает коллекцию в качестве аргумента:

List<SomeBean> wsListCopy=new ArrayList<SomeBean>(wsList);  
person Abhay Yadav    schedule 14.01.2013

Вы можете использовать addAll ().

eg : wsListCopy.addAll(wsList);

person samaludheen cignes    schedule 03.01.2018

Я не вижу правильного ответа. Если вам нужна глубокая копия, вам нужно выполнить итерацию и скопировать объект вручную (вы можете использовать конструктор копирования).

person The incredible Jan    schedule 27.04.2018
comment
Это один из немногих настоящих ответов здесь. Дополнительные сведения: stackoverflow.com/questions/715650/ - person cellepo; 12.08.2018

re: indexOutOfBoundsException, проблема с аргументами подсписка; вам нужно закончить подсписок размером-1. Поскольку отсчитывается от нуля, последний элемент списка всегда имеет размер-1, в позиции размера нет элемента, отсюда и ошибка.

person Jon Nelson    schedule 10.10.2013

Вам следует использовать метод addAll. Он добавляет все элементы указанной коллекции в конец списка копирования. Это будет копия вашего списка.

List<String> myList = new ArrayList<>();
myList.add("a");
myList.add("b");
List<String> copyList = new ArrayList<>();
copyList.addAll(myList);
person XGsm Prj    schedule 04.12.2020

Функция subList - это уловка, возвращаемый объект все еще находится в исходном списке. поэтому, если вы выполните какую-либо операцию в subList, это вызовет одновременное исключение в вашем коде, независимо от того, является ли это однопоточным или многопоточным.

person weixingsun    schedule 04.06.2015