8.2Manipulation des collections
8.2.1 – Ajout, suppression, recherche
Les collections Java fournissent de nombreuses méthodes pour manipuler les éléments : ajouter, supprimer, rechercher, et bien plus encore.
➕ Ajout d'éléments
Exemple : Ajout dans une List
import java.util.ArrayList;
import java.util.List;
List<String> liste = new ArrayList<>();
// Ajouter des éléments
liste.add("Alice"); // Ajoute Ă la fin
liste.add("Bob");
liste.add(0, "Charlie"); // Ajoute à l'index 0 (déplace les autres)
System.out.println(liste); // Affiche : [Charlie, Alice, Bob]
➖ Suppression d'éléments
Exemple : Suppression dans une List
List<String> liste = new ArrayList<>();
liste.add("Alice");
liste.add("Bob");
liste.add("Charlie");
// Supprimer par valeur
liste.remove("Alice"); // Supprime "Alice"
// Supprimer par index
liste.remove(0); // Supprime l'élément à l'index 0
// Supprimer tous les éléments
liste.clear(); // Vide la liste
🔍 Recherche d'éléments
Exemple : Recherche dans une List
List<String> liste = new ArrayList<>();
liste.add("Alice");
liste.add("Bob");
liste.add("Charlie");
// Vérifier si un élément existe
boolean existe = liste.contains("Alice"); // true
// Trouver l'index d'un élément
int index = liste.indexOf("Bob"); // 1
int dernierIndex = liste.lastIndexOf("Bob"); // Si plusieurs occurrences
// Vérifier si la liste est vide
boolean vide = liste.isEmpty(); // false
// Obtenir la taille
int taille = liste.size(); // 3
🗺️ Manipulation d'une Map
Exemple : Opérations sur une Map
import java.util.HashMap;
import java.util.Map;
Map<String, Integer> ages = new HashMap<>();
// Ajouter/Modifier
ages.put("Alice", 25);
ages.put("Bob", 30);
ages.put("Alice", 26); // Remplace la valeur précédente
// Obtenir une valeur
Integer ageAlice = ages.get("Alice"); // 26
Integer ageInconnu = ages.get("Charlie"); // null (clé inexistante)
// Vérifier l'existence d'une clé ou valeur
boolean aClé = ages.containsKey("Alice"); // true
boolean aValeur = ages.containsValue(30); // true
// Supprimer
ages.remove("Bob"); // Supprime la clé "Bob"
ages.remove("Alice", 25); // Supprime seulement si la valeur correspond
// Taille
int taille = ages.size(); // Nombre de paires clé-valeur
🔢 Manipulation d'un Set
Exemple : Opérations sur un Set
import java.util.HashSet;
import java.util.Set;
Set<String> uniques = new HashSet<>();
// Ajouter
uniques.add("Alice");
uniques.add("Bob");
uniques.add("Alice"); // Ignoré (déjà présent)
// Rechercher
boolean existe = uniques.contains("Alice"); // true
// Supprimer
uniques.remove("Bob");
// Taille
int taille = uniques.size(); // 1
8.2.2 – Parcours d'une collection
Il existe plusieurs façons de parcourir une collection en Java : boucle for-each, Iterator, et méthodes forEach (Java 8+).
🔄 Boucle for-each (recommandée)
La boucle for-each est la méthode la plus simple et la plus lisible pour parcourir une collection.
Exemple : Parcours avec for-each
List<String> liste = new ArrayList<>();
liste.add("Alice");
liste.add("Bob");
liste.add("Charlie");
// Parcours simple
for (String element : liste) {
System.out.println(element);
}
// Parcours d'une Map
Map<String, Integer> ages = new HashMap<>();
ages.put("Alice", 25);
ages.put("Bob", 30);
// Parcourir les clés
for (String nom : ages.keySet()) {
System.out.println(nom);
}
// Parcourir les valeurs
for (Integer age : ages.values()) {
System.out.println(age);
}
// Parcourir les paires clé-valeur
for (Map.Entry<String, Integer> entry : ages.entrySet()) {
System.out.println(entry.getKey() + " : " + entry.getValue());
}
🔍 Iterator
L'Iterator permet un contrôle plus fin sur le parcours, notamment pour supprimer des éléments pendant l'itération.
Exemple : Parcours avec Iterator
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
List<String> liste = new ArrayList<>();
liste.add("Alice");
liste.add("Bob");
liste.add("Charlie");
// Parcours avec Iterator
Iterator<String> it = liste.iterator();
while (it.hasNext()) {
String element = it.next();
System.out.println(element);
}
// Supprimer pendant l'itération (sécurisé)
Iterator<String> it2 = liste.iterator();
while (it2.hasNext()) {
String element = it2.next();
if (element.equals("Bob")) {
it2.remove(); // Supprime l'élément courant
}
}
↔️ ListIterator - Parcours bidirectionnel
Le ListIterator est une interface qui étend Iterator et permet de parcourir une liste dans les deux sens (avant et arrière). Il offre également des fonctionnalités supplémentaires comme l'ajout et la modification d'éléments pendant le parcours.
🔑 Caractéristiques de ListIterator
- Parcours bidirectionnel : Peut parcourir la liste vers l'avant et vers l'arrière
- Accès à l'index : Permet d'obtenir l'index de l'élément courant
- Modification : Permet d'ajouter, modifier et supprimer des éléments
- Spécifique aux List : Fonctionne uniquement avec les implémentations de
List(ArrayList, LinkedList, etc.)
📋 Méthodes principales de ListIterator
hasNext(): Vérifie s'il y a un élément suivantnext(): Retourne l'élément suivant et avance le curseurhasPrevious(): Vérifie s'il y a un élément précédentprevious(): Retourne l'élément précédent et recule le curseurnextIndex(): Retourne l'index de l'élément suivantpreviousIndex(): Retourne l'index de l'élément précédent
add(E element): Ajoute un élément à la position couranteset(E element): Remplace l'élément retourné parnext()ouprevious()remove(): Supprime l'élément retourné parnext()ouprevious()
➡️ Parcours vers l'avant
Exemple : Parcours classique vers l'avant
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
List<String> liste = new ArrayList<>();
liste.add("Alice");
liste.add("Bob");
liste.add("Charlie");
// Créer un ListIterator
ListIterator<String> it = liste.listIterator();
// Parcourir vers l'avant
while (it.hasNext()) {
String element = it.next();
int index = it.previousIndex(); // Index de l'élément courant (après next())
System.out.println("Index " + index + " : " + element);
}
// Affiche :
// Index 0 : Alice
// Index 1 : Bob
// Index 2 : Charlie
⬅️ Parcours vers l'arrière
Exemple : Parcours vers l'arrière
List<String> liste = new ArrayList<>();
liste.add("Alice");
liste.add("Bob");
liste.add("Charlie");
// Créer un ListIterator positionné à la fin
ListIterator<String> it = liste.listIterator(liste.size());
// Parcourir vers l'arrière
while (it.hasPrevious()) {
String element = it.previous();
int index = it.nextIndex(); // Index de l'élément suivant (après previous())
System.out.println("Index " + index + " : " + element);
}
// Affiche :
// Index 2 : Charlie
// Index 1 : Bob
// Index 0 : Alice
↔️ Parcours dans les deux sens
Exemple : Parcours aller-retour
List<String> liste = new ArrayList<>();
liste.add("Alice");
liste.add("Bob");
liste.add("Charlie");
liste.add("David");
ListIterator<String> it = liste.listIterator();
// Parcourir vers l'avant jusqu'au milieu
System.out.println("Parcours vers l'avant :");
while (it.nextIndex() < liste.size() / 2) {
System.out.println(it.next());
}
// Affiche : Alice, Bob
// Maintenant parcourir vers l'arrière
System.out.println("\nParcours vers l'arrière :");
while (it.hasPrevious()) {
System.out.println(it.previous());
}
// Affiche : Bob, Alice
➕ Ajouter des éléments avec ListIterator
Exemple : Ajout d'éléments pendant le parcours
List<String> liste = new ArrayList<>();
liste.add("Alice");
liste.add("Bob");
liste.add("Charlie");
ListIterator<String> it = liste.listIterator();
// Parcourir et ajouter des éléments
while (it.hasNext()) {
String element = it.next();
if (element.equals("Bob")) {
// Ajouter un élément après "Bob"
it.add("Bobette"); // Ajoute Ă la position courante
}
}
System.out.println(liste);
// Affiche : [Alice, Bob, Bobette, Charlie]
add()insère l'élément avant l'élément qui serait retourné parnext()- Après
add(), l'appel Ănext()ne serait pas affectĂ© - L'appel Ă
previous()retournerait le nouvel élément ajouté
✏️ Modifier des éléments avec ListIterator
Exemple : Modification d'éléments
List<String> liste = new ArrayList<>();
liste.add("alice");
liste.add("bob");
liste.add("charlie");
ListIterator<String> it = liste.listIterator();
// Parcourir et mettre en majuscules
while (it.hasNext()) {
String element = it.next();
// Modifier l'élément courant
it.set(element.toUpperCase()); // Remplace l'élément retourné par next()
}
System.out.println(liste);
// Affiche : [ALICE, BOB, CHARLIE]
set()remplace l'Ă©lĂ©ment retournĂ© par le dernier appel Ănext()ouprevious()- Vous devez appeler
next()ouprevious()avant d'appelerset() - Vous ne pouvez pas appeler
set()aprèsadd()ouremove()sans avoir appelénext()ouprevious()entre les deux
🗑️ Supprimer des éléments avec ListIterator
Exemple : Suppression pendant le parcours
List<String> liste = new ArrayList<>();
liste.add("Alice");
liste.add("Bob");
liste.add("Charlie");
liste.add("David");
ListIterator<String> it = liste.listIterator();
// Supprimer les éléments qui commencent par "C"
while (it.hasNext()) {
String element = it.next();
if (element.startsWith("C")) {
it.remove(); // Supprime l'élément retourné par next()
}
}
System.out.println(liste);
// Affiche : [Alice, Bob, David]
📍 Positionnement du ListIterator
Vous pouvez créer un ListIterator à une position spécifique :
List<String> liste = new ArrayList<>();
liste.add("Alice");
liste.add("Bob");
liste.add("Charlie");
liste.add("David");
// Créer un ListIterator à l'index 2 (après "Bob")
ListIterator<String> it = liste.listIterator(2);
// L'élément suivant sera "Charlie"
System.out.println(it.next()); // Affiche : Charlie
// L'élément précédent sera "Bob"
it.previous();
System.out.println(it.previous()); // Affiche : Bob
đź’» Exemple complet : Traitement bidirectionnel
Exemple : Inverser une liste avec ListIterator
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class InversionListe {
public static void main(String[] args) {
List<String> liste = new ArrayList<>();
liste.add("A");
liste.add("B");
liste.add("C");
liste.add("D");
System.out.println("Liste originale : " + liste);
// Inverser avec ListIterator
ListIterator<String> avant = liste.listIterator();
ListIterator<String> arriere = liste.listIterator(liste.size());
// Échanger les éléments de chaque côté
while (avant.nextIndex() < arriere.previousIndex()) {
String temp = avant.next();
avant.set(arriere.previous());
arriere.set(temp);
}
System.out.println("Liste inversée : " + liste);
// Affiche : Liste inversée : [D, C, B, A]
}
}
📊 Comparaison : Iterator vs ListIterator
| Fonctionnalité | Iterator | ListIterator |
|---|---|---|
| Parcours avant | âś… Oui | âś… Oui |
| Parcours arrière | ❌ Non | ✅ Oui |
| Accès à l'index | ❌ Non | ✅ Oui (nextIndex, previousIndex) |
| Ajouter des éléments | ❌ Non | ✅ Oui (add) |
| Modifier des éléments | ❌ Non | ✅ Oui (set) |
| Supprimer des éléments | ✅ Oui | ✅ Oui |
| Collections supportées | Toutes | List uniquement |
⚠️ Erreurs communes à éviter
Erreur 1 : Appeler set() sans next() ou previous()
ListIterator<String> it = liste.listIterator();
// ❌ ERREUR : IllegalStateException
// it.set("Nouveau"); // Pas d'élément courant défini
// âś… CORRECT
it.next(); // Définir l'élément courant
it.set("Nouveau"); // Maintenant OK
Erreur 2 : Mélanger add() et remove() sans next()/previous()
ListIterator<String> it = liste.listIterator();
it.next();
it.add("Nouveau");
// ❌ ERREUR : IllegalStateException
// it.remove(); // Pas d'élément courant après add()
// âś… CORRECT
it.next(); // Avancer après add()
it.remove(); // Maintenant OK
Erreur 3 : Utiliser ListIterator sur une collection non-List
Set<String> set = new HashSet<>();
// ❌ ERREUR : Set n'a pas de méthode listIterator()
// ListIterator<String> it = set.listIterator();
// âś… CORRECT : Utiliser Iterator pour Set
Iterator<String> it = set.iterator();
💡 Points clés à retenir
- ListIterator : Permet le parcours bidirectionnel des listes
- Parcours avant :
hasNext()etnext() - Parcours arrière :
hasPrevious()etprevious() - Index :
nextIndex()etpreviousIndex()pour obtenir les positions - Ajout :
add()insère un élément à la position courante - Modification :
set()remplace l'élément courant - Suppression :
remove()supprime l'élément courant - Positionnement :
listIterator(index)crée un itérateur à une position spécifique - Spécifique aux List : Ne fonctionne qu'avec les implémentations de
List
- Utilisez
ListIteratorquand vous avez besoin de parcourir une liste dans les deux sens - Idéal pour des algorithmes qui nécessitent de revenir en arrière (parsing, traitement bidirectionnel)
- Très utile pour modifier des éléments pendant le parcours (mise en majuscules, transformation, etc.)
- N'oubliez pas d'appeler
next()ouprevious()avantset()ouremove() - Pour un parcours simple en avant,
Iteratoroufor-eachsuffisent
🆕 Méthode forEach (Java 8+)
Depuis Java 8, vous pouvez utiliser la méthode forEach avec des expressions lambda.
Exemple : Parcours avec forEach
List<String> liste = new ArrayList<>();
liste.add("Alice");
liste.add("Bob");
liste.add("Charlie");
// forEach avec lambda
liste.forEach(element -> System.out.println(element));
// forEach avec référence de méthode
liste.forEach(System.out::println);
// forEach sur une Map
Map<String, Integer> ages = new HashMap<>();
ages.put("Alice", 25);
ages.put("Bob", 30);
ages.forEach((nom, age) ->
System.out.println(nom + " : " + age)
);
📊 Comparaison des méthodes de parcours
| Méthode | Avantages | Inconvénients | Cas d'usage |
|---|---|---|---|
| for-each | Simple, lisible, sûr | Pas de suppression directe | Parcours simple en lecture |
| Iterator | Contrôle fin, suppression sécurisée | Plus verbeux | Parcours avec suppression |
| ListIterator | Parcours bidirectionnel, ajout/modification | Spécifique aux List, plus complexe | Parcours avant/arrière, modifications |
| forEach | Concis, fonctionnel | Nécessite Java 8+ | Parcours avec lambda |
💡 Points clés à retenir
- for-each : Méthode la plus simple pour un parcours en lecture
- Iterator : Pour un contrôle fin et la suppression sécurisée
- ListIterator : Pour un parcours bidirectionnel et des modifications avancées (List uniquement)
- forEach : Style fonctionnel avec lambda (Java 8+)
- Modification : Utilisez Iterator/ListIterator pour modifier pendant le parcours
- Map : Utilisez keySet(), values(), ou entrySet() pour parcourir