Bonjour ! Dans la leçon précédente, nous avons exploré les tableaux, une structure de données puissante mais limitée par sa taille fixe. Cette contrainte est souvent un frein dans les applications réelles où le nombre de données à gérer peut varier.
Aujourd'hui, nous allons découvrir la solution à ce problème en nous plongeant dans la classe ArrayList. C'est votre premier pas dans le Framework des Collections Java, un ensemble d'outils essentiels pour tout développeur backend. L'objectif de cette leçon est de vous apprendre à utiliser ArrayList pour créer et manipuler des listes dynamiques d'objets, une compétence que vous utiliserez quotidiennement.
1. Des tableaux fixes aux listes dynamiques
La principale faiblesse d'un tableau classique (String[], int[], etc.) est que sa taille est définie une fois pour toutes. Si vous déclarez un tableau de 10 éléments et que vous avez besoin d'en stocker un onzième, vous êtes bloqué. ArrayList a été conçu pour résoudre précisément ce problème.
Regardez le début de cette vidéo qui illustre parfaitement le passage du tableau statique à l'ArrayList.
APPRENDRE LE JAVA #11 - LES ARRAYLISTS
Cette vidéo de la chaîne Graven - Développement, intitulée "APPRENDRE LE JAVA #11 - LES ARRAYLISTS", commence par un excellent rappel des limites des tableaux.
Concentrez-vous sur la première partie de la vidéo, l'introduction, où le problème de ArrayIndexOutOfBoundsException est présenté et l'ArrayList est introduite comme solution.
Un ArrayList est une classe qui implémente l'interface List. Pensez-y comme à un "tableau amélioré" qui présente les caractéristiques suivantes :
- Taille dynamique : Il grandit et rétrécit automatiquement pour s'adapter au nombre d'éléments.
- Ordonnée : Il conserve l'ordre dans lequel les éléments sont insérés.
- Autorise les doublons : Vous pouvez y stocker plusieurs fois le même élément.
2. Déclaration et utilisation des génériques
Pour créer un ArrayList, vous devez importer la classe depuis java.util et utiliser une syntaxe spécifique qui introduit un concept crucial en Java : les génériques (generics).
Les génériques, représentés par des chevrons (< >), permettent de spécifier le type de données que votre liste contiendra. C'est une mesure de sécurité essentielle qui empêche de mélanger différents types de données par erreur.
// Importation nécessaire au début de votre fichier
import java.util.ArrayList;
import java.util.List; // Bonne pratique d'importer l'interface aussi
public class Main {
public static void main(String[] args) {
// Déclaration d'un ArrayList qui ne contiendra que des chaînes de caractères (String)
ArrayList<String> noms = new ArrayList<>();
// Déclaration en utilisant l'interface List (meilleure pratique)
// Cela rend votre code plus flexible si vous décidez de changer pour une autre implémentation de List plus tard
List<Integer> notes = new ArrayList<>();
}
}
Bonne pratique : Depuis Java 7, vous pouvez utiliser l'opérateur "diamant" (<>) dans la partie droite de l'initialisation. Le compilateur déduit le type à partir de la déclaration, ce qui allège le code. C'est la syntaxe que vous devriez toujours utiliser.
3. Les opérations fondamentales (CRUD)
Comme pour toute structure de données, vous devez savoir comment créer, lire, mettre à jour et supprimer des éléments (CRUD : Create, Read, Update, Delete). ArrayList fournit des méthodes très intuitives pour cela.
La vidéo suivante vous montrera en action les méthodes les plus courantes.
APPRENDRE LE JAVA #11 - LES ARRAYLISTS
Continuons avec la vidéo de Graven - Développement.
Regardez les segments suivants pour voir une démonstration pratique des opérations de base : Ajouter des éléments avec la méthode add(). Lire un élément avec la méthode get(). Supprimer des éléments avec remove() et clear(). Méthodes utiles comme size() pour la taille et contains() pour la recherche. L'importance des génériques pour la sécurité de type.
Pour une référence textuelle complète que vous pourrez consulter plus tard, l'article suivant est excellent.
ArrayList en Java - Tutoriel Complet : Déclaration, Manipulation et Bonnes Pratiques
Cet article de Rachid Saad Academy est un guide très détaillé sur ArrayList.
Concentrez-vous sur les sections "2. Premiers pas avec ArrayList" pour revoir la déclaration et "3. Les Opérations Fondamentales (CRUD)" qui détaille avec des exemples de code les méthodes add(), get(), set(), remove() et contains().
Voici un tableau récapitulatif des méthodes essentielles :
| Opération | Méthode(s) | Description |
|---|---|---|
| Ajouter | add(element)add(index, element) |
Ajoute un élément à la fin ou à un index spécifique. |
| Lire | get(index) |
Récupère l'élément à l'index donné. |
| Modifier | set(index, element) |
Remplace l'élément à un index donné par un nouvel élément. |
| Supprimer | remove(index)remove(object)clear() |
Supprime un élément par son index, par sa valeur, ou vide toute la liste. |
| Utilitaires | size()isEmpty()contains(object) |
Retourne la taille, vérifie si la liste est vide, vérifie la présence d'un élément. |
4. Sous le capot : le redimensionnement automatique
Comment ArrayList réussit-il à être "dynamique" ? Votre expérience en développement vous amène sûrement à vous poser cette question. La réponse est que, en interne, il utilise un tableau classique. Lorsque ce tableau interne est plein, ArrayList en crée un nouveau, plus grand, et y copie tous les anciens éléments avant d'ajouter le nouvel élément.

Ce processus est efficace mais a un coût en performance. Si vous savez à l'avance que vous allez stocker un grand nombre d'éléments, vous pouvez optimiser en spécifiant une capacité initiale lors de la création de la liste. Cela permet d'éviter de multiples opérations de redimensionnement coûteuses.
// Crée une ArrayList avec une capacité initiale de 1000 éléments.
// Aucune opération de redimensionnement ne sera faite avant le 1001ème ajout.
List<String> utilisateurs = new ArrayList<>(1000);
5. Utiliser ArrayList avec vos propres objets
Jusqu'à présent, nous avons utilisé des types simples comme String ou Integer. Mais la véritable puissance de ArrayList se révèle lorsque vous l'utilisez avec vos propres classes, comme Utilisateur, Produit ou Commande.
class Produit {
private String nom;
private double prix;
public Produit(String nom, double prix) {
this.nom = nom;
this.prix = prix;
}
// ... getters et setters ...
}
List<Produit> catalogue = new ArrayList<>();
catalogue.add(new Produit("Laptop Pro", 1499.99));
catalogue.add(new Produit("Souris Gamer", 79.50));
Lorsque vous faites cela, il y a deux méthodes que vous devez impérativement redéfinir (@Override) dans votre classe (Produit dans cet exemple) pour que les collections se comportent correctement.
toString(): Pour un affichage lisible. Si vous ne la redéfinissez pas, unSystem.out.println(catalogue)affichera une liste de références mémoire peu utiles (ex:[Produit@1b6d3586, Produit@4554617c]).equals()ethashCode(): Pour la recherche et la comparaison. Des méthodes commecontains()etremove(objet)utilisentequals()pour trouver l'objet dans la liste. Sans une redéfinition correcte, Java compare les références mémoire, pas le contenu des objets. Deux objetsProduitavec le même nom et le même prix ne seront pas considérés comme égaux !
La ressource suivante explique ce point crucial avec un excellent exemple.
ArrayList en Java - Tutoriel Complet : Déclaration, Manipulation et Bonnes Pratiques
Cet article couvre parfaitement l'utilisation d'ArrayList avec des objets personnalisés.
Lisez attentivement la section "6. Manipuler des ArrayList d'Objets Personnalisés". Portez une attention particulière aux sous-sections 6.2 et 6.3 qui expliquent pourquoi et comment redéfinir toString(), equals() et hashCode().
6. Exercice pratique : Gestionnaire de tâches
Mettons tout cela en pratique. Vous allez créer un petit gestionnaire de tâches.
Énoncé :
- Créez une classe
Tacheavec les attributsdescription(String) etestTerminee(boolean). - Dans la classe
Tache, redéfinissez :- Le constructeur pour initialiser une tâche avec sa description (par défaut,
estTermineeserafalse). toString()pour afficher la tâche de manière claire (par ex:[X] Faire les coursesou[ ] Apprendre Java).equals()ethashCode()basés sur ladescriptionpour que deux tâches avec la même description soient considérées comme identiques. Votre IDE (IntelliJ ou VS Code) peut générer ces méthodes pour vous.
- Le constructeur pour initialiser une tâche avec sa description (par défaut,
- Créez une classe principale
GestionnaireTachesavec une méthodemain. - Dans le
main, créez uneArrayList<Tache>nomméetaches. - Ajoutez-y 3 ou 4 tâches.
- Affichez toutes les tâches en utilisant une boucle
for-each. - "Terminez" une des tâches en y accédant via son index (
get()) et en appelant un setter pour modifier son statut. - Affichez de nouveau toutes les tâches pour voir le changement.
- Vérifiez si une tâche spécifique existe en utilisant
contains()sur un nouvel objetTache. - Supprimez une des tâches par son index ou sa valeur et affichez la liste finale.
Cliquez ici pour voir une proposition de solution
Classe Tache.java
import java.util.Objects;
public class Tache {
private String description;
private boolean estTerminee;
public Tache(String description) {
this.description = description;
this.estTerminee = false;
}
public String getDescription() {
return description;
}
public boolean isEstTerminee() {
return estTerminee;
}
public void setEstTerminee(boolean estTerminee) {
this.estTerminee = estTerminee;
}
@Override
public String toString() {
return (estTerminee ? "[X] " : "[ ] ") + description;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Tache tache = (Tache) o;
return Objects.equals(description, tache.description);
}
@Override
public int hashCode() {
return Objects.hash(description);
}
}
Classe GestionnaireTaches.java
import java.util.ArrayList;
import java.util.List;
public class GestionnaireTaches {
public static void main(String[] args) {
List<Tache> taches = new ArrayList<>();
// Ajout de tâches
taches.add(new Tache("Apprendre les ArrayLists en Java"));
taches.add(new Tache("Faire l'exercice pratique"));
taches.add(new Tache("Préparer la réunion de demain"));
taches.add(new Tache("Acheter du café"));
System.out.println("--- Liste de tâches initiale ---");
for (Tache tache : taches) {
System.out.println(tache);
}
// Marquer une tâche comme terminée
System.out.println("\n> On termine la deuxième tâche...");
taches.get(1).setEstTerminee(true);
System.out.println("\n--- Liste de tâches mise à jour ---");
for (Tache tache : taches) {
System.out.println(tache);
}
// Vérifier l'existence d'une tâche
Tache recherche = new Tache("Acheter du café");
System.out.println("\n> La liste contient-elle la tâche 'Acheter du café' ? " + taches.contains(recherche));
// Supprimer une tâche
System.out.println("\n> On supprime la tâche à l'index 0...");
taches.remove(0);
System.out.println("\n--- Liste de tâches finale ---");
for (Tache tache : taches) {
System.out.println(tache);
}
System.out.println("\nNombre final de tâches : " + taches.size());
}
}
Conclusion
Aujourd'hui, vous avez ajouté une structure de données fondamentale et extrêmement polyvalente à votre boîte à outils Java. ArrayList sera votre choix par défaut dans de très nombreuses situations.
Points clés à retenir :
ArrayListest une liste dynamique et ordonnée qui résout le problème de taille fixe des tableaux.- L'utilisation des génériques (
ArrayList<Type>) est non négociable pour garantir la sécurité de votre code. - Les méthodes de base (
add,get,set,remove,size) sont simples et puissantes. - Le redimensionnement automatique a un coût en performance ; l'utilisation d'une capacité initiale peut être une optimisation judicieuse.
- Pour utiliser
ArrayListavec vos propres classes, vous devez redéfinirtoString(),equals()ethashCode()pour un comportement correct.
Dans les prochaines leçons, nous continuerons notre exploration du Framework des Collections. Nous découvrirons HashMap, pour stocker des paires clé-valeur, et HashSet, pour garantir l'unicité des éléments. Vous apprendrez ainsi à choisir la structure de données la plus adaptée à chaque problème.