Como copiar um java.util.List para outro java.util.List

135

Eu tenho um List<SomeBean>que é preenchido a partir de um serviço da Web. Quero copiar / clonar o conteúdo dessa lista em uma lista vazia do mesmo tipo. Uma pesquisa no Google para copiar uma lista sugeriu que eu usasse o Collections.copy()método Em todos os exemplos que vi, a lista de destinos deveria conter o número exato de itens para a cópia ocorrer.

Como a lista que estou usando é preenchida por um serviço da Web e contém centenas de objetos, não posso usar a técnica acima. Ou eu estou usando errado ?? !! De qualquer forma, para fazê-lo funcionar, tentei fazer algo assim, mas ainda consegui IndexOutOfBoundsException.

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

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

Tentei usar o wsListCopy=wsList.subList(0, wsList.size())mas obtive um ConcurrentAccessExceptioncódigo mais tarde. Sucesso e julgamento. :)

Enfim, minha pergunta é simples, como posso copiar todo o conteúdo da minha lista em outra lista? Não através da iteração, é claro.

Mono Jamoon
fonte
11
Qualquer cópia usará a iteração, é claro. Você pode escondê-lo, mas ele ainda estará lá.
precisa saber é o seguinte
1
Primeiro de tudo: você tem certeza de que precisa copiar essa lista? Qual é a sua motivação para fazer isso?
ppeterka
2
Sim, a iteração está apenas oculta sob essas camadas. Mas o comentário foi adicionado para evitar qualquer resposta de iteração. :)
Mono Jamoon
@ppeterka Estou executando operações na lista, como removeAll (). Isso faz com que a lista perca seus dados originais. E "esses dados" também são necessários posteriormente.
precisa saber é o seguinte
Qual é o tipo real de uma lista que está retornando app.allInOne(template)? ArrayList?
Andremoniy

Respostas:

235

Apenas use isto:

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

Nota: ainda não é seguro para threads, se você modificar a otherListpartir de outro thread, convém tornar isso otherList(e até newList) um CopyOnWriteArrayList, por exemplo - ou usar uma primitiva de bloqueio, como ReentrantReadWriteLock, para serializar o acesso de leitura / gravação a qualquer lista. acessado simultaneamente.

fge
fonte
1
Agora, eu me sinto muito idiota :) Espero que construí-lo dessa maneira não atinja nenhum ConcurrentAccessException.
precisa saber é o seguinte
5
+1 se ele estiver recebendo ConcurrentModifcationException, ele tem um problema de simultaneidade que precisa corrigir primeiro.
precisa saber é o seguinte
5
Por que essa resposta está ganhando tantos pontos se a pergunta menciona "copiar / clonar"? Isso, desde que outras respostas não tenham nada a ver com clonagem. As mesmas referências serão mantidas para os objetos dentro das coleções, independentemente dos métodos de utilidade específicos da coleção / fluxo que você usar.
Yuranos # 9/16
3
A resposta está errada. O conteúdo não é copiado. Apenas são referências.
A incrível Jan
33

Esta é uma ótima maneira do Java 8:

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

Obviamente, a vantagem aqui é que você pode filtrar e pular para copiar apenas parte da lista.

por exemplo

//don't copy the first element 
List<String> list2 = list1.stream().skip(1).collect(Collectors.toList());
Dan
fonte
4
a lista resultante é uma cópia profunda ou superficial da lista original?
Ad Infinitum
7
Uma cópia superficial.
kap
3
Infelizmente, isso também não é seguro para threads. Supondo que listseja alterado enquanto o coletor estiver em execução, a ConcurrentModificationExceptionserá lançada.
C-Otto
@ Dan, como pular a cópia do último elemento?
CKM
@chandresh para pular copiar o último elemento, você iria usar apenas.limit(list1.size() - 1)
Matthew Carpenter
13
originalArrayList.addAll(copyArrayofList);

Lembre-se de sempre que usar o método addAll () para copiar, o conteúdo das referências das listas de matriz (originalArrayList e copyArrayofList) aos mesmos objetos será adicionado à lista; portanto, se você modificar qualquer um deles, o copyArrayofList também será refletem a mesma mudança.

Se você não quiser efeito colateral, precisará copiar cada elemento do originalArrayList para o copyArrayofList, como usar um loop for ou while.

Divyesh Kanzariya
fonte
2
Esta é uma das poucas respostas verdadeiras aqui, pois especifica que #addAll faz uma cópia superficial e também como copiar em profundidade. Mais detalhes: stackoverflow.com/questions/715650/…
cellepo
7

Tentei fazer algo assim, mas ainda recebi uma IndexOutOfBoundsException.

Eu recebi uma ConcurrentAccessException

Isso significa que você está modificando a lista enquanto tenta copiá-la, provavelmente em outro segmento. Para consertar isso, você deve

  • use uma coleção projetada para acesso simultâneo.

  • bloqueie a coleção adequadamente para que você possa iterá-la (ou permitir que você chame um método que faça isso por você)

  • encontre uma distância para evitar a necessidade de copiar a lista original.

Peter Lawrey
fonte
4

A partir do Java 10 :

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

List.copyOf()retorna um não modificável Listcontendo os elementos do dado Collection.

O dado Collectionnão deve ser nulle não deve conter nenhum nullelemento.

Além disso, se você deseja criar uma cópia profunda de a List, pode encontrar muitas boas respostas aqui .

Oleksandr Pyrohov
fonte
3

Há outro método com o Java 8 de maneira segura para nulos.

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

Se você quiser pular um elemento.

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

Com o Java 9+, o método de fluxo de Opcional pode ser usado

Optional.ofNullable(wsList)
    .stream()
    .flatMap(Collection::stream)
    .collect(Collectors.toList())
Nicolas Henneaux
fonte
1

Eu estava tendo o mesmo problema ConcurrentAccessException e mysolution:

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

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

Portanto, ele funciona apenas uma operação por vez e evita a exceção ...

T04435
fonte
1

Tentei algo semelhante e consegui reproduzir o problema (IndexOutOfBoundsException). Abaixo estão minhas descobertas:

1) A implementação do Collections.copy (destList, sourceList) primeiro verifica o tamanho da lista de destinos chamando o método size (). Como a chamada para o método size () sempre retornará o número de elementos na lista (0 neste caso), o construtor ArrayList (capacidade) garante apenas a capacidade inicial da matriz de backup e isso não tem nenhuma relação com o tamanho da lista. Portanto, sempre obtemos IndexOutOfBoundsException.

2) Uma maneira relativamente simples é usar o construtor que usa uma coleção como argumento:

List<SomeBean> wsListCopy=new ArrayList<SomeBean>(wsList);  
Abhay Yadav
fonte
0

re indexOutOfBoundsException:, seus argumentos da sub-lista são o problema; você precisa finalizar a sublist no tamanho 1. Sendo baseado em zero, o último elemento de uma lista é sempre o tamanho 1, não há elemento na posição do tamanho, daí o erro.

Jon Nelson
fonte
0

Você pode usar addAll ().

por exemplo : wsListCopy.addAll(wsList);

samaludheen cignes
fonte
0

Não consigo ver nenhuma resposta correta. Se você quiser uma cópia profunda, precisará iterar e copiar o objeto manualmente (você pode usar um construtor de cópias).

O incrível Jan
fonte
Esta é uma das poucas respostas verdadeiras aqui. Mais detalhes: stackoverflow.com/questions/715650/…
cellepo
-2

Se você não deseja que alterações em uma lista efetuem outra, tente isso. Funcionou para mim
Espero que isso ajude.

  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
fonte
-3

função subList é um truque, o objeto retornado ainda está na lista original. portanto, se você executar qualquer operação na subList, ela causará a exceção simultânea no seu código, independentemente de ser um único thread ou vários threads.

weixingsun
fonte