1. Introduction
En programmation, nous sommes constamment confrontés à des situations où, à partir d’un grand ensemble de données, il faut ne sélectionner que les éléments nécessaires — c’est ce qu’on appelle le filtrage. Vous voulez ne garder que les nombres pairs, trouver les chaînes contenant le mot "Java" ou sélectionner les utilisateurs de plus de 18 ans — tout cela relève du filtrage.
En Java, ces opérations apparaissent à chaque étape, il est donc important de maîtriser en confiance les différentes façons de les réaliser et d’en comprendre les particularités.
2. Filtrage à l’aide d’une boucle
Commençons par la méthode la plus basique — une boucle for classique. Cette approche est dite impérative, car vous indiquez explicitement quoi faire et comment le faire. Elle se lit bien et est simple à comprendre.
Exemple : ne garder que les nombres pairs
import java.util.*;
public class FilterExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
List<Integer> evenNumbers = new ArrayList<>(); // Nous créons une nouvelle liste pour le résultat
for (Integer n : numbers) {
if (n % 2 == 0) { // On vérifie la condition: nombre pair
evenNumbers.add(n);
}
}
System.out.println("Nombres pairs: " + evenNumbers);
}
}
Résultat :
Nombres pairs: [2, 4, 6, 8, 10]
Il est important de se souvenir que la collection d’origine (numbers) ne change pas. Nous construisons une nouvelle liste de résultats.
Exemple : filtrer des chaînes par sous-chaîne
List<String> words = Arrays.asList("java", "python", "javascript", "kotlin", "c++");
List<String> javaWords = new ArrayList<>();
for (String word : words) {
if (word.contains("java")) {
javaWords.add(word);
}
}
System.out.println(javaWords); // [java, javascript]
Même principe : on parcourt la liste de chaînes et on vérifie la présence de la sous-chaîne à l’aide de la méthode contains.
3. Suppression d’éléments d’une collection : pourquoi ce n’est pas si simple ?
Où est le piège ?
Parfois, on veut supprimer de la collection d’origine tous les éléments inutiles. Mais si vous essayez de le faire pendant un parcours en for-each, vous obtiendrez une exception ConcurrentModificationException.
List<Integer> numbers = new ArrayList<>(Arrays.asList(1, -2, 3, -4, 5));
for (Integer n : numbers) {
if (n < 0) {
numbers.remove(n); // DANGEREUX! ConcurrentModificationException!
}
}
Résultat :
Exception in thread "main" java.util.ConcurrentModificationException
Les collections n’aiment pas être modifiées pendant un tel parcours — cela casse l’itération.
Comment supprimer correctement des éléments d’une collection ?
Méthode 1 : utiliser Iterator.remove()
List<Integer> numbers = new ArrayList<>(Arrays.asList(1, -2, 3, -4, 5));
Iterator<Integer> it = numbers.iterator();
while (it.hasNext()) {
Integer n = it.next();
if (n < 0) {
it.remove(); // Suppression en toute sécurité!
}
}
System.out.println(numbers); // [1, 3, 5]
Ici, nous créons un itérateur via la méthode iterator(), nous parcourons la collection avec hasNext() et next(), et nous supprimons les éléments inutiles en appelant it.remove().
Méthode 2 : créer une nouvelle liste contenant uniquement les éléments souhaités
List<Integer> numbers = Arrays.asList(1, -2, 3, -4, 5);
List<Integer> positive = new ArrayList<>();
for (Integer n : numbers) {
if (n >= 0) {
positive.add(n);
}
}
System.out.println(positive); // [1, 3, 5]
Nous ne touchons pas à la collection d’origine et nous construisons une nouvelle liste. L’approche est sûre, claire et s’étend facilement lorsque les conditions se complexifient.
Méthode 3 : utiliser removeIf (Java 8+)
List<Integer> numbers = new ArrayList<>(Arrays.asList(1, -2, 3, -4, 5));
numbers.removeIf(n -> n < 0);
System.out.println(numbers); // [1, 3, 5]
En une seule ligne, nous passons la condition : « supprime tout ce qui est inférieur à zéro ». Les détails internes d’une modification sûre sont pris en charge par la collection.
En résumé : pour supprimer des éléments, n’utilisez pas for-each. Choisissez entre Iterator.remove(), la création d’une nouvelle liste ou le concis removeIf.
4. Quand utiliser quelle méthode pour filtrer ?
L’approche impérative via une boucle simple est pratique lorsque vous devez non seulement sélectionner des éléments, mais aussi faire immédiatement quelque chose avec eux (par exemple, les afficher ou les transformer). Elle est simple et transparente.
S’il s’agit précisément de suppression depuis la collection d’origine, évitez de supprimer dans un for-each. Utilisez Iterator.remove() pour un contrôle pas à pas, ou le moderne removeIf() — la méthode la plus courte et expressive.
Exemple : on a une liste de mots, il faut supprimer tous les mots de moins de quatre caractères :
List<String> words = new ArrayList<>(Arrays.asList("Java", "is", "fun", "awesome", "code"));
words.removeIf(word -> word.length() < 4);
System.out.println(words); // [Java, awesome, code]
La méthode removeIf accepte un prédicat — une règle de filtrage — et supprime tout ce qui le satisfait.
5. Erreurs courantes lors du filtrage des collections
Erreur n° 1 : tentative de supprimer des éléments d’une collection dans une boucle for-each.
Ce code conduira à une ConcurrentModificationException :
for (Integer n : numbers) {
if (n < 0) {
numbers.remove(n); // BOUM! ConcurrentModificationException
}
}
Solutions correctes : utilisez Iterator.remove() ou removeIf.
Erreur n° 2 : condition de filtrage mal formulée.
Il faut supprimer uniquement les nombres négatifs :
List<Integer> numbers = new ArrayList<>(Arrays.asList(-3, -1, 0, 2, 4));
numbers.removeIf(n -> n < 0);
System.out.println(numbers); // [0, 2, 4]
Mais si, par erreur, vous écrivez « non positifs » et utilisez <=, alors zéro disparaîtra aussi :
numbers.removeIf(n -> n <= 0); // Résultat: [2, 4] — zéro supprimé par erreur
Soyez attentif à la précision des conditions : une seule comparaison erronée change complètement le résultat.
GO TO FULL VERSION