Comment copier une java.util.List dans une autre java.util.List

135

J'ai un List<SomeBean>qui est rempli à partir d'un service Web. Je souhaite copier / cloner le contenu de cette liste dans une liste vide du même type. Une recherche Google pour copier une liste m'a suggéré d'utiliser la Collections.copy()méthode. Dans tous les exemples que j'ai vus, la liste de destination était censée contenir le nombre exact d'éléments pour que la copie ait lieu.

Comme la liste que j'utilise est remplie via un service Web et qu'elle contient des centaines d'objets, je ne peux pas utiliser la technique ci-dessus. Ou je l'utilise mal ?? !! Bref, pour que ça marche, j'ai essayé de faire quelque chose comme ça, mais j'en ai quand même 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());

J'ai essayé d'utiliser le wsListCopy=wsList.subList(0, wsList.size())mais j'ai obtenu un ConcurrentAccessExceptionplus tard dans le code. Frappe et procès. :)

Quoi qu'il en soit, ma question est simple, comment puis-je copier tout le contenu de ma liste dans une autre liste? Pas par itération, bien sûr.

Mono Jamoon
la source
11
Toute copie utilisera bien sûr une itération. Vous pouvez le cacher mais il sera toujours là.
Peter Lawrey
1
Tout d'abord: êtes-vous sûr de devoir copier cette liste? Quelle est votre motivation à faire cela?
ppeterka
2
Ouais, l'itération est juste cachée sous ces couches. Mais le commentaire a été ajouté pour empêcher toute réponse d'itération. :)
Mono Jamoon
@ppeterka J'effectue des opérations sur la liste, comme removeAll (). Cela provoque la liste de perdre ses données d'origine. Et «ces données» sont également requises par la suite.
Mono Jamoon
Quel est le type réel d'une liste, qui revient par app.allInOne(template)? ArrayList?
Andremoniy le

Réponses:

235

Utilisez simplement ceci:

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

Remarque: toujours pas thread-safe, si vous modifiez à otherListpartir d'un autre thread, vous voudrez peut-être en faire otherList(et même newList) un CopyOnWriteArrayList, par exemple - ou utiliser une primitive de verrouillage, telle que ReentrantReadWriteLock pour sérialiser l'accès en lecture / écriture à toutes les listes. accédé simultanément.

fge
la source
1
Maintenant, je me sens vraiment stupide :) J'espère que le construire comme ça n'en jetterait pas ConcurrentAccessException.
Mono Jamoon
5
+1 s'il obtient ConcurrentModifcationException, il a un problème de concurrence qu'il doit d'abord résoudre.
Peter Lawrey
5
Pourquoi cette réponse obtient-elle autant de points si la question mentionnait "copier / cloner"? Ceci, tant que certaines autres réponses n'ont rien à voir avec le clonage. Les mêmes références seront conservées pour les objets à l'intérieur des collections, quelles que soient les méthodes utilitaires spécifiques à la collection / flux que vous utilisez.
yuranos
3
La réponse est fausse. Le contenu n'est pas copié. Seulement c'est des références.
L'incroyable
33

C'est une très belle façon de faire Java 8:

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

Bien sûr, l'avantage ici est que vous pouvez filtrer et ignorer uniquement une partie de la liste.

par exemple

//don't copy the first element 
List<String> list2 = list1.stream().skip(1).collect(Collectors.toList());
Dan
la source
4
la liste résultante est-elle une copie profonde ou superficielle de la liste originale?
Ad Infinitum
7
Une copie superficielle.
kap
3
Ceci, malheureusement, n'est pas non plus thread-safe. En supposant que listest modifié pendant que le collecteur est en cours d'exécution, un ConcurrentModificationExceptionest lancé.
C-Otto
@Dan, Comment ignorer la copie du dernier élément?
CKM
@chandresh pour ignorer la copie du dernier élément, il vous suffit d'utiliser.limit(list1.size() - 1)
Matthew Carpenter
13
originalArrayList.addAll(copyArrayofList);

Veuillez garder à l'esprit chaque fois que vous utilisez la méthode addAll () pour copier, le contenu des références des listes de tableaux (originalArrayList et copyArrayofList) aux mêmes objets sera ajouté à la liste, donc si vous modifiez l'un d'entre eux, copyArrayofList le sera également reflètent le même changement.

Si vous ne voulez pas d'effet secondaire, vous devez copier chaque élément de l'originalArrayList vers le copyArrayofList, comme en utilisant une boucle for ou while.

Divyesh Kanzariya
la source
2
C'est l'une des rares vraies réponses ici, car elle spécifie que #addAll fait une copie superficielle, ainsi que la façon de copier en profondeur. Plus de détails: stackoverflow.com/questions/715650/…
cellepo
7

J'ai essayé de faire quelque chose comme ça, mais j'ai toujours une IndexOutOfBoundsException.

J'ai une ConcurrentAccessException

Cela signifie que vous modifiez la liste pendant que vous essayez de la copier, probablement dans un autre thread. Pour résoudre ce problème, vous devez soit

  • utilisez une collection conçue pour un accès simultané.

  • verrouiller la collection de manière appropriée afin que vous puissiez la parcourir (ou vous permettre d'appeler une méthode qui le fait pour vous)

  • trouver un moyen d'éviter d'avoir à copier la liste originale.

Peter Lawrey
la source
4

À partir de Java 10 :

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

List.copyOf()renvoie un Listélément non modifiable contenant les éléments du donné Collection.

Le donné Collectionne doit pas être nullet ne doit contenir aucun nullélément.

De plus, si vous souhaitez créer une copie complète d'un List, vous pouvez trouver de nombreuses bonnes réponses ici .

Oleksandr Pyrohov
la source
3

Il existe une autre méthode avec Java 8 de manière sûre pour les valeurs nulles.

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

Si vous souhaitez ignorer un élément.

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

Avec Java 9+, la méthode de flux facultative peut être utilisée

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

J'avais le même problème ConcurrentAccessException et mysolution était de:

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

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

Cela ne fonctionne donc qu'une seule opération à la fois et évite l'exeption ...

T04435
la source
1

J'ai essayé quelque chose de similaire et j'ai pu reproduire le problème (IndexOutOfBoundsException). Voici mes conclusions:

1) L'implémentation de Collections.copy (destList, sourceList) vérifie d'abord la taille de la liste de destination en appelant la méthode size (). Puisque l'appel à la méthode size () retournera toujours le nombre d'éléments de la liste (0 dans ce cas), le constructeur ArrayList (capacité) assure uniquement la capacité initiale du tableau de sauvegarde et cela n'a aucun rapport avec le taille de la liste. Par conséquent, nous obtenons toujours IndexOutOfBoundsException.

2) Un moyen relativement simple consiste à utiliser le constructeur qui prend une collection comme argument:

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

re indexOutOfBoundsException:, vos arguments de sous-liste sont le problème; vous devez terminer la sous-liste à la taille 1. Étant de base zéro, le dernier élément d'une liste est toujours size-1, il n'y a pas d'élément dans la position de taille, d'où l'erreur.

Jon Nelson
la source
0

Vous pouvez utiliser addAll ().

par exemple : wsListCopy.addAll(wsList);

samaludheen cignes
la source
0

Je ne vois aucune réponse correcte. Si vous voulez une copie complète, vous devez itérer et copier l'objet manuellement (vous pouvez utiliser un constructeur de copie).

L'incroyable Jan
la source
C'est l'une des rares vraies réponses ici. Plus de détails: stackoverflow.com/questions/715650/…
cellepo
-2

Si vous ne voulez pas que les changements dans une liste affectent une autre liste, essayez ceci. Cela a fonctionné pour moi
J'espère que cela aide.

  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
la source
-3

La fonction subList est une astuce, l'objet retourné est toujours dans la liste d'origine. donc si vous effectuez une opération dans subList, cela provoquera l'exception simultanée dans votre code, qu'il s'agisse d'un thread unique ou d'un multi thread.

weixingsun
la source