1. Classe ArrayList
En Java, l’interface List est un contrat : « Je suis une collection ordonnée d’éléments, et on peut obtenir un élément par son numéro (indice). »
Propriétés clés d’une liste (List) :
- Les éléments sont stockés dans un ordre défini (contrairement à un ensemble).
- On peut stocker des éléments en double (par exemple : deux fois "Vasya").
- On peut accéder à un élément par son indice : le premier élément a l’indice 0, le second — 1, et ainsi de suite.
- On peut ajouter et supprimer des éléments à n’importe quel endroit de la liste.
L’implémentation la plus populaire de l’interface List est ArrayList. En coulisses, elle utilise un tableau classique et s’agrandit automatiquement à mesure que les données augmentent.
Comment créer ArrayList ?
import java.util.ArrayList;
import java.util.List;
public class Example {
public static void main(String[] args) {
// Créons une liste de chaînes
List<String> students = new ArrayList<>();
}
}
Explication
- List<String> est une variable de type « liste de chaînes ». On déclare la variable via l’interface et on crée l’objet via une classe concrète (ArrayList).
- Les chevrons <String> définissent le type des éléments de la liste (génériques, generics).
Méthodes de base de ArrayList (et de tout List) :
- add(element) — ajoute un élément à la fin de la liste.
- add(index, element) — insère un élément à un indice donné.
- get(index) — obtient l’élément par son indice.
- set(index, element) — remplace l’élément à l’indice donné.
- remove(index) — supprime l’élément à l’indice donné.
- remove(Object) — supprime le premier élément trouvé, égal à l’objet passé.
- size() — renvoie le nombre d’éléments dans la liste.
Exemple : nous travaillons avec une liste d’étudiants
import java.util.ArrayList;
import java.util.List;
public class StudentListDemo {
public static void main(String[] args) {
List<String> students = new ArrayList<>();
// Ajout des étudiants
students.add("Vasya");
students.add("Petya");
students.add("Masha");
// Afficher tous les étudiants
System.out.println("Liste des étudiants: " + students);
// Récupérer le premier étudiant
String first = students.get(0);
System.out.println("Premier étudiant: " + first);
// Changer le nom du deuxième étudiant
students.set(1, "Pavel");
System.out.println("Après modification: " + students);
// Supprimer Masha
students.remove("Masha");
System.out.println("Après suppression de Masha: " + students);
// Taille de la liste
System.out.println("Nombre total d'etudiants: " + students.size());
}
}
Résultat :
Liste des étudiants: [Vasya, Petya, Masha]
Premier étudiant: Vasya
Après modification: [Vasya, Pavel, Masha]
Après suppression de Masha: [Vasya, Pavel]
Nombre total d’étudiants: 2
Quel est le lien avec notre application ?
Supposons que nous avons une application de suivi des tâches d’un étudiant. Nous pouvons désormais stocker la liste des tâches comme List<String>, et non comme un tableau, et ajouter des tâches dynamiquement.
2. Classe LinkedList : quand l’insertion et la suppression rapides comptent
LinkedList est une implémentation alternative de liste. Elle est organisée en chaîne doublement chaînée : chaque nœud connaît les éléments précédent et suivant. Comme dans une rame de train : insérer un « wagon » au milieu est rapide et ne nécessite pas de réorganiser toute la rame.
Création de LinkedList
import java.util.LinkedList;
import java.util.List;
public class Example {
public static void main(String[] args) {
List<String> tasks = new LinkedList<>();
}
}
Particularités de LinkedList
- Insertion et suppression rapides au début et au milieu de la liste.
- Accès par indice lent (pour trouver le 100e élément, il faut parcourir la chaîne).
- Adaptée si vous ajoutez/supprimez souvent des éléments non seulement à la fin, mais aussi au début ou au milieu.
Exemple : utilisation de LinkedList
import java.util.LinkedList;
import java.util.List;
public class TaskListDemo {
public static void main(String[] args) {
List<String> tasks = new LinkedList<>();
tasks.add("Se réveiller");
tasks.add("Prendre le petit-déjeuner");
tasks.add("Aller en cours");
// Ajouter une tâche au début
tasks.add(0, "Régler le réveil");
System.out.println("Liste des tâches: " + tasks);
// Supprimer la première tâche (la plus ancienne)
tasks.remove(0);
System.out.println("Après suppression de la première tâche: " + tasks);
}
}
3. Comparaison d’ArrayList et de LinkedList
| Critère | |
|
|---|---|---|
| Base | Tableau | Liste doublement chaînée |
| Accès rapide par indice | Oui (O(1)) | Non (O(n)) |
| Insertion/suppression rapide au début/au milieu | Non (O(n)) | Oui (O(1) — si l’on a une référence) |
| Insertion/suppression rapide en fin de liste | Oui (généralement O(1)) | Oui (O(1)) |
| Mémoire | Consomme moins de mémoire | Plus (références supplémentaires vers les voisins) |
| Cas d’usage typiques | Accès fréquent par indice | Insertions/suppressions fréquentes |
Règle simple :
- Vous avez besoin d’un accès rapide par indice — utilisez ArrayList.
- Vous ajoutez/supprimez souvent au début ou au milieu — utilisez LinkedList.
4. Opérations typiques sur les listes
Parcourir les éléments d’une liste
Boucle for classique
for (int i = 0; i < students.size(); i++) {
System.out.println("Étudiant #" + i + ": " + students.get(i));
}
Boucle for-each (la plus courante)
for (String name : students) {
System.out.println("Nom: " + name);
}
Expression lambda (Java 8+)
students.forEach(name -> System.out.println("Nom: " + name));
Recherche d’éléments
- contains(element) — renvoie true si l’élément est présent dans la liste.
- indexOf(element) — renvoie l’indice de la première occurrence de l’élément, sinon -1.
if (students.contains("Vasya")) {
System.out.println("Vasya est dans la liste!");
}
int index = students.indexOf("Vasya");
System.out.println("Indice de Vasya: " + index);
Vidage de la liste
clear() — supprime tous les éléments.
students.clear();
System.out.println("Liste après effacement: " + students);
5. Quand utiliser ArrayList et quand LinkedList ?
Le plus simple est de raisonner ainsi : ArrayList est adapté quand il faut accéder rapidement aux éléments par indice et que la liste change peu. Par exemple, une longue liste d’utilisateurs ou l’historique des messages — principalement en lecture.
À l’inverse, LinkedList est utile lorsque vous insérez ou supprimez souvent des éléments au début/au milieu. Cela peut être une file, une pile ou un historique d’annulations.
En pratique, on utilise le plus souvent ArrayList. Et LinkedList reste « l’outil au cas où » : il reste dans le tiroir, mais c’est parfois exactement ce qu’il faut.
6. Erreurs courantes lors du travail avec les listes
Erreur n° 1 : dépassement des bornes de la liste. La situation la plus fréquente est l’accès à un indice inexistant. Si la liste contient trois éléments et que vous écrivez students.get(5), vous obtiendrez une IndexOutOfBoundsException. Vérifiez size() avant l’accès.
Erreur n° 2 : suppression d’un élément pendant l’itération. Lors d’un parcours avec for-each et une suppression simultanée d’éléments, vous obtiendrez une ConcurrentModificationException. Pour des suppressions complexes, utilisez une boucle par indice ou un Iterator.
Erreur n° 3 : comparaison incorrecte d’objets. Si vous stockez vos propres objets (par exemple, Student), les méthodes contains et remove s’appuient sur equals. S’il n’est pas redéfini, la comparaison se fera par référence et non par contenu.
Erreur n° 4 : utilisation de types bruts. N’écrivez pas List list = new ArrayList() — indiquez toujours le type des éléments : List<String> list = new ArrayList<>(). Les génériques protègent des erreurs et rendent le code plus clair.
GO TO FULL VERSION