Suppression d'éléments des collections Java

1. Vue d'ensemble

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

Nous examinerons naturellement également certaines des mises en garde.

2. Définition de notre collection

Tout d'abord, nous allons illustrer deux approches qui modifient la structure de données d'origine. 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 names = new ArrayList(); names.add("John"); names.add("Ana"); names.add("Mary"); names.add("Anthony"); names.add("Mark");

3. Suppression d'éléments avec itérateur

L' Iterator de Java nous permet à la fois de parcourir et de supprimer chaque élément individuel d'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 à l'aide de next et les supprimer en utilisant remove :

Iterator 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 à prendre en compte:

  • En fonction de la collection, nous pouvons rencontrer des exceptions ConcurrentModificationException
  • Nous devons parcourir les éléments avant de pouvoir les supprimer
  • 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 tandis que LinkedList.Iterator ajuste simplement le pointeur vers l'élément suivant. En tant que tel, LinkedList.Iterator fonctionne bien mieux que ArrayList.Iterator lors de la suppression d'éléments

4. Java 8 et Collection.removeIf ()

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

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

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

Dans Java 8, ArrayList remplace l'implémentation par défaut - qui repose sur Iterator - et implémente une stratégie différente: d'abord, il itère sur les éléments et marque ceux qui correspondent à notre prédicat; ensuite, il répète une seconde fois pour supprimer (et décaler) les éléments marqués lors de la première itération.

5. Java 8 et l'introduction de Stream

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

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

5.1. Suppression d'éléments avec Stream

Supprimer, ou plutôt filtrer des éléments à l'aide de Stream est assez simple , il suffit de créer une instance de Stream à l' aide de notre collection , d'appeler le filtre avec notre prédicat , puis de collecter le résultat à l'aide de collecteurs:

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

Le streaming est moins invasif que les approches précédentes, il favorise l'isolement et permet la création de plusieurs copies à 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 à la fois d'éléments correspondants et non correspondants. Dans de tels cas, nous pouvons profiter de Collectors.partitioningBy :

Map
    
      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 un Map qui ne contient que deux clés, true et false , chacune pointant vers une liste contenant respectivement les éléments correspondants et non correspondants.

6. Conclusion

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

Vous pouvez trouver le code source complet et tous les extraits de code pour cet article sur GitHub.