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.


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.


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

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.


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.


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í .


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

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 ...


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

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.




-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]

-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.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.