Conversion d'une collection en ArrayList en Java

1. Vue d'ensemble

La conversion de collections Java d'un type à un autre est une tâche de programmation courante. Dans ce didacticiel, nous allons convertir tout type de collection en ArrayList .

Tout au long du didacticiel, nous supposerons que nous avons déjà une collection d' objets Foo . À partir de là, nous allons créer une ArrayList en utilisant différentes approches.

2. Définir notre exemple

Mais avant de continuer, modélisons nos entrées et sorties.

Notre source peut être n'importe quel type de collection, nous allons donc la déclarer en utilisant l' interface Collection :

Collection srcCollection; 

Nous devons produire une ArrayList avec le même type d'élément:

ArrayList newList;

3. Utilisation du constructeur ArrayList

Le moyen le plus simple de copier une collection dans une nouvelle collection consiste à utiliser son constructeur.

Dans notre précédent guide sur ArrayList, nous avons appris que le constructeur ArrayList peut accepter un paramètre de collection:

ArrayList newList = new ArrayList(srcCollection);
  • Le nouveau ArrayList contient une copie superficielle des éléments Foo dans la collection source.
  • L'ordre est le même que celui de la collection source.

La simplicité du constructeur en fait une excellente option dans la plupart des scénarios.

4. Utilisation de l'API Streams

Maintenant, profitons de l'API Streams pour créer une ArrayList à partir d'une collection existante :

ArrayList newList = srcCollection.stream().collect(toCollection(ArrayList::new));

Dans cet extrait:

  • Nous prenons le flux de la collection source et appliquons l' opérateur collect () pour créer une liste
  • Nous spécifions ArrayList :: new pour obtenir le type de liste que nous voulons
  • Ce code produira également une copie superficielle.

Si nous n'étions pas préoccupés par le type de liste exact , nous pourrions simplifier:

List newList = srcCollection.stream().collect(toList());

Notez que toCollection () et toList () sont importés statiquement depuis Collectors . Pour en savoir plus, veuillez consulter notre guide sur les collecteurs de Java 8.

5. Copie profonde

Avant, nous parlions de «copies superficielles». Par cela, nous voulons dire que les éléments de la nouvelle liste sont exactement les mêmes instances Foo qui existent toujours dans la collection source. Par conséquent, nous avons copié les Foo dans la newList par référence.

Si nous modifions le contenu d'une instance Foo dans l'une ou l'autre des collections, cette modification sera reflétée dans les deux collections . Par conséquent, si nous voulons modifier les éléments de l'une ou l'autre des collections sans modifier l'autre, nous devons effectuer une «copie complète».

Pour copier en profondeur un Foo , nous créons une toute nouvelle instance Foo pour chaque élément . Par conséquent, tous les champs Foo doivent être copiés dans les nouvelles instances.

Définissons notre classe Foo afin qu'elle sache comment se copier en profondeur:

public class Foo { private int id; private String name; private Foo parent; public Foo(int id, String name, Foo parent) { this.id = id; this.name = name; this.parent = parent; } public Foo deepCopy() { return new Foo( this.id, this.name, this.parent != null ? this.parent.deepCopy() : null); } }

Ici, nous pouvons voir que les champs id et name sont int et String . Ces types de données sont copiés par valeur. Par conséquent, nous pouvons simplement attribuer les deux.

Le champ parent est un autre Foo , qui est une classe. Si Foo était muté, tout code partageant cette référence serait affecté par ces changements. Nous devons copier en profondeur le champ parent .

Nous pouvons maintenant revenir à notre conversion ArrayList . Nous avons juste besoin de l' opérateur de carte pour insérer la copie complète dans le flux:

ArrayList newList = srcCollection.stream() .map(foo -> foo.deepCopy()) .collect(toCollection(ArrayList::new));

Nous pouvons modifier le contenu de l'une ou l'autre des collections sans affecter l'autre.

Une copie complète peut être un processus long en fonction du nombre d'éléments et de la profondeur des données. L'utilisation d'un flux parallèle ici peut améliorer les performances si nécessaire.

6. Contrôle de l'ordre des listes

Par défaut, notre flux fournira des éléments à notre ArrayList dans le même ordre qu'ils sont rencontrés dans la collection source.

Si nous voulons changer cet ordre, nous pouvons appliquer l' opérateur sorted () au flux . Pour trier nos objets Foo par nom:

ArrayList newList = srcCollection.stream() .sorted(Comparator.comparing(Foo::getName)) .collect(toCollection(ArrayList::new));

Nous pouvons trouver plus de détails sur l'ordre des flux dans ce tutoriel précédent.

7. Conclusion

Le constructeur ArrayList est un moyen efficace d'obtenir le contenu d'une Collection dans un nouvel ArrayList .

However, if we need to tweak the resulting list, the Streams API provides a powerful way to modify the process.

The code used in this article can be found in its entirety over on GitHub.