Suppression des éléments des collections Java

Vue d’ensemble

Dans ce rapide tutoriel, nous allons parler de quatre façons différentes de supprimer les éléments des collections Java qui correspondent à certains prédicats.

Nous allons naturellement aussi examiner certaines des mises en garde.

Définir notre collection

D’abord, nous allons illustrer deux approches qui mutent la structure de données originale. Ensuite, nous parlerons de deux autres options qui, au lieu de supprimer les éléments, créeront une copie de la Collection originale sans eux.

Utilisons la collection suivante tout au long de nos exemples pour montrer comment nous pouvons obtenir le même résultat en utilisant différentes méthodes :

Collection<String> names = new ArrayList<>();names.add("John");names.add("Ana");names.add("Mary");names.add("Anthony");names.add("Mark");

Suppression d’éléments avec l’Iterator

L’Iterator de Java nous permet à la fois de parcourir et de supprimer chaque élément individuel dans une Collection.

Pour ce faire, nous devons d’abord récupérer un itérateur sur ses éléments en utilisant la méthode iterator. Ensuite, nous pouvons visiter chaque élément avec l’aide de next et les retirer en utilisant remove:

Iterator<String> i = names.iterator();while(i.hasNext()) { String e = i.next(); if (e.startsWith("A")) { i.remove(); }}

Malgré sa simplicité, il y a quelques mises en garde que nous devrions considérer:

  • Selon la collection, nous pouvons rencontrer des exceptions ConcurrentModificationException
  • Nous devons itérer sur les éléments avant de pouvoir les retirer
  • Selon la collection, remove peut se comporter différemment que prévu. Par exemple : ArrayList.Iterator supprime l’élément de la collection et décale les données suivantes vers la gauche alors que, LinkedList.Iterator ajuste simplement le pointeur vers l’élément suivant. En tant que tel, LinkedList.Iterator se comporte beaucoup mieux que ArrayList.Iterator lors de la suppression d’éléments

Java 8 et Collection.removeIf()

Java 8 a introduit une nouvelle méthode à l’interface Collection qui fournit un moyen plus concis de supprimer des éléments en utilisant Predicate:

names.removeIf(e -> e.startsWith("A"));

Il est important de noter que contrairement à l’approche Iterator, removeIf se comporte de manière similaire dans LinkedList et ArrayList.

En Java 8, ArrayList outrepasse l’implémentation par défaut – qui repose sur Iterator – et met en œuvre une stratégie différente : d’abord, il itère sur les éléments et marque ceux qui correspondent à notre prédicat ; ensuite, il itère une deuxième fois pour supprimer (et décaler) les éléments qui ont été marqués lors de la première itération.

Java 8 et l’introduction du Stream

L’une des nouvelles fonctionnalités majeures de Java 8 était l’ajout du Stream (et des collecteurs). Il existe de nombreuses façons de créer un Stream à partir d’une source. Cependant, la plupart des opérations qui affectent l’instance Stream ne mutent pas sa source, l’API se concentre plutôt sur la création de copies d’une source et l’exécution de toute opération dont nous pouvons avoir besoin dans celles-ci.

Regardons comment nous pouvons utiliser Stream et Collectors pour trouver/filtrer les éléments qui correspondent, et ne correspondent pas, à notre prédicat.

5.1. Suppression d’éléments avec Stream

La suppression, ou plutôt le filtrage d’éléments à l’aide de Stream est assez simple, il suffit de créer une instance de Stream à l’aide de notre Collection, d’invoquer le filtre avec notre Prédicat, puis de collecter le résultat à l’aide des Collecteurs :

Collection<String> filteredCollection = names .stream() .filter(e -> !e.startsWith("A")) .collect(Collectors.toList());

Le Stream est moins invasif que les approches précédentes, il favorise l’isolation et permet la création de copies multiples à partir de la même source. Cependant, nous devons garder à l’esprit qu’il augmente également la mémoire utilisée par notre application.

5.2. Collectors.partitioningBy

Combiner à la fois Stream.filter et Collectors est assez pratique, bien que nous puissions rencontrer des scénarios où nous avons besoin d’éléments correspondants et non correspondants. Dans de tels cas, nous pouvons profiter de Collectors.partitioningBy:

Map<Boolean, List<String>> classifiedElements = names .stream() .collect(Collectors.partitioningBy((String e) -> !e.startsWith("A")));String matching = String.join(",", classifiedElements.get(true));String nonMatching = String.join(",", classifiedElements.get(false));

Cette méthode renvoie une Map qui ne contient que deux clés, true et false, chacune pointant vers une liste qui contient les éléments correspondants, et non correspondants, respectivement.

Conclusion

Dans cet article, nous avons examiné quelques méthodes pour retirer des éléments des Collections et certaines de leurs mises en garde.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée.