Cómo copiar un java.util.List en otro java.util.List

135

Tengo un List<SomeBean>que se completa desde un servicio web. Quiero copiar / clonar el contenido de esa lista en una lista vacía del mismo tipo. Una búsqueda en Google para copiar una lista me sugirió usar el Collections.copy()método. En todos los ejemplos que vi, se suponía que la lista de destinos debía contener el número exacto de elementos para que se realizara la copia.

Como la lista que estoy usando se completa a través de un servicio web y contiene cientos de objetos, no puedo usar la técnica anterior. ¿O lo estoy usando mal? De todos modos, para que funcione, intenté hacer algo como esto, pero todavía obtuve un IndexOutOfBoundsException.

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

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

Traté de usar el wsListCopy=wsList.subList(0, wsList.size())pero obtuve uno ConcurrentAccessExceptionmás tarde en el código. Golpe y juicio. :)

De todos modos, mi pregunta es simple, ¿cómo puedo copiar todo el contenido de mi lista en otra lista? No a través de la iteración, por supuesto.

Mono Jamoon
fuente
11
Cualquier copia usará la iteración, por supuesto. Puedes esconderlo pero seguirá estando allí.
Peter Lawrey
1
En primer lugar: ¿estás seguro de que necesitas copiar esa lista? ¿Cuál es tu motivación para hacer eso?
ppeterka
2
Sí, la iteración está oculta debajo de esas capas. Pero se agregó el comentario para evitar cualquier respuesta de iteración. :)
Mono Jamoon
@ppeterka Estoy realizando operaciones en la lista, como removeAll (). Esto hace que la lista pierda sus datos originales. Y "esos datos" también se requieren después.
Mono Jamoon
¿Cuál es el tipo real de una lista que está regresando app.allInOne(template)? ArrayList?
Andremoniy

Respuestas:

235

Solo usa esto:

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

Nota: aún no es seguro para subprocesos, si modifica otherListdesde otro subproceso, entonces es posible que desee hacer eso otherList(e incluso newList) un CopyOnWriteArrayList, por ejemplo, o usar un primitivo de bloqueo, como ReentrantReadWriteLock para serializar el acceso de lectura / escritura a las listas que estén Acceso concurrente.

fge
fuente
1
Ahora, me siento realmente estúpido :) Espero que construirlo así no arroje nada ConcurrentAccessException.
Mono Jamoon
55
+1 si obtiene ConcurrentModifcationException, tiene un problema de concurrencia que primero debe solucionar.
Peter Lawrey
55
¿Por qué esta respuesta obtiene tantos puntos si la pregunta menciona "copiar / clonar"? Esto, siempre que otras respuestas no tengan nada que ver con la clonación. Se mantendrán las mismas referencias para los objetos dentro de las colecciones, independientemente de los métodos de utilidad específicos de la colección / secuencia que utilice.
yuranos
3
La respuesta es incorrecta. El contenido no se copia. Solo son referencias.
El increíble Jan
33

Esta es una forma muy agradable de Java 8 para hacerlo:

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

Por supuesto, la ventaja aquí es que puede filtrar y saltar a solo una copia de parte de la lista.

p.ej

//don't copy the first element 
List<String> list2 = list1.stream().skip(1).collect(Collectors.toList());
Dan
fuente
44
¿Es la lista resultante una copia profunda o superficial de la lista original?
Ad Infinitum
77
Una copia superficial.
kap
3
Esto, lamentablemente, tampoco es seguro para subprocesos. Suponiendo que listse cambia mientras el recopilador se está ejecutando, ConcurrentModificationExceptionse lanza a.
C-Otto
@ Dan, ¿Cómo omitir copiar el último elemento?
CKM
@chandresh para omitir la copia del último elemento, simplemente usarías.limit(list1.size() - 1)
Matthew Carpenter
13
originalArrayList.addAll(copyArrayofList);

Tenga en cuenta que siempre que use el método addAll () para copiar, el contenido de las referencias de las listas de matriz (originalArrayList y copyArrayofList) a los mismos objetos se agregará a la lista, por lo que si modifica alguno de ellos, copyArrayofList también Refleja el mismo cambio.

Si no desea efectos secundarios, debe copiar cada uno de los elementos de la OriginalArrayList a la copyArrayofList, como usar un bucle for o while.

Divyesh Kanzariya
fuente
2
Esta es una de las pocas respuestas verdaderas aquí, ya que especifica que #addAll realiza una copia superficial, así como también cómo copiar en profundidad. Más detalles: stackoverflow.com/questions/715650/…
cellepo
7

Intenté hacer algo como esto, pero aún obtuve una IndexOutOfBoundsException.

Tengo una ConcurrentAccessException

Esto significa que está modificando la lista mientras intenta copiarla, probablemente en otro hilo. Para arreglar esto tienes que

  • use una colección diseñada para acceso concurrente.

  • bloquee la colección adecuadamente para que pueda iterar sobre ella (o permitirle llamar a un método que lo haga por usted)

  • encuentre un lugar alejado para evitar tener que copiar la lista original.

Peter Lawrey
fuente
4

A partir de Java 10 :

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

List.copyOf()devuelve un no modificable que Listcontiene los elementos de lo dado Collection.

Lo dado Collectionno debe ser null, y no debe contener ningún nullelemento.

Además, si desea crear una copia profunda de un List, puede encontrar muchas buenas respuestas aquí .

Oleksandr Pyrohov
fuente
3

Hay otro método con Java 8 de forma segura.

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

Si quieres saltarte un elemento.

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

Con Java 9+, se puede usar el método de transmisión de Opcional

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

Estaba teniendo el mismo problema ConcurrentAccessException y mysolution era:

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

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

Por lo tanto, funciona solo una operación a la vez y evita la Excepción ...

T04435
fuente
1

Intenté algo similar y pude reproducir el problema (IndexOutOfBoundsException). A continuación se encuentran mis hallazgos:

1) La implementación de Collections.copy (destList, sourceList) primero verifica el tamaño de la lista de destino llamando al método size (). Dado que la llamada al método size () siempre devolverá el número de elementos en la lista (0 en este caso), el constructor ArrayList (capacidad) asegura solo la capacidad inicial de la matriz de respaldo y esto no tiene ninguna relación con el Tamaño de la lista. Por lo tanto, siempre obtenemos IndexOutOfBoundsException.

2) Una forma relativamente simple es usar el constructor que toma una colección como argumento:

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

re:, indexOutOfBoundsExceptionsus argumentos de sublista son el problema; debe finalizar la sublista en tamaño-1. Al estar basado en cero, el último elemento de una lista siempre es tamaño-1, no hay ningún elemento en la posición de tamaño, de ahí el error.

Jon Nelson
fuente
0

Puede usar addAll ().

p.ej : wsListCopy.addAll(wsList);

cigarros samaludheen
fuente
0

No puedo ver ninguna respuesta correcta. Si desea una copia profunda, debe iterar y copiar el objeto manualmente (podría usar un constructor de copia).

El increíble Jan
fuente
Esta es una de las pocas respuestas verdaderas aquí. Más detalles: stackoverflow.com/questions/715650/…
cellepo
-2

Si no desea que los cambios en una lista afecten a otra lista, intente esto. Funcionó para mí
Espero que esto ayude.

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

La función subList es un truco, el objeto devuelto todavía está en la lista original. por lo tanto, si realiza alguna operación en subList, causará la excepción concurrente en su código, sin importar si es un solo hilo o un hilo múltiple.

weixingsun
fuente