Как скопировать 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?
Andremoniy

Ответы:

235

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

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

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

FGE
источник
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
является ли результирующий список полной или неглубокой копией исходного списка?
Объявление Infinitum
7
Мелкая копия.
kap
3
К сожалению, это также не безопасно. Предполагается, listчто изменяется во время работы коллектора, а ConcurrentModificationExceptionвыбрасывается.
C-Otto
@Dan, как пропустить копирование последнего элемента?
CKM
@chandresh, чтобы пропустить копирование последнего элемента, вы бы просто использовали.limit(list1.size() - 1)
Мэтью Карпентер
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

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

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

T04435
источник
1

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

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

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

List<SomeBean> wsListCopy=new ArrayList<SomeBean>(wsList);  
Абхай Ядав
источник
0

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

Джон Нельсон
источник
0

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

например: wsListCopy.addAll(wsList);

Самалудхин Cignes
источник
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, это вызовет одновременное исключение в вашем коде, независимо от того, является ли это однопоточным или многопоточным.

weixingsun
источник