ArrayList — Listes dynamiques en Java
Prérequis
Maîtriser les tableaux classiques et la classe Arrays. Comprendre les types génériques (diamond operator <>). Connaître les classes wrapper (Integer, Double, etc.).
Objectifs
Comprendre l'intérêt des listes dynamiques par rapport aux tableaux classiques. Maîtriser la création, l'ajout, la suppression, la modification et le parcours d'une ArrayList. Connaître les différences fondamentales entre tableaux et ArrayList.
1. Qu'est-ce qu'une ArrayList ?
ArrayList est une classe du Java Collections Framework qui implémente une liste dynamique redimensionnable. Contrairement aux tableaux classiques, sa taille peut changer pendant l'exécution du programme — elle s'agrandit automatiquement lors de l'ajout d'éléments et se contracte lors de leur suppression.
La classe ArrayList offre plusieurs avantages par rapport aux tableaux classiques :
- Taille dynamique : pas besoin de connaître la taille à l'avance
- Ajout automatique : la capacité s'adapte automatiquement
- Suppression flexible : les éléments peuvent être supprimés à tout moment
- Méthodes puissantes :
add(),remove(),get(),set(),size(), etc.
ArrayList ne peut contenir que des objets, pas des types primitifs. Pour stocker des valeurs primitives (int, double, boolean, etc.), on utilise les classes wrapper (Integer, Double, Boolean, etc.). L'autoboxing convertit automatiquement les primitifs en objets.
2. Déclaration et création
import java.util.ArrayList; // ou import java.util.*;
// Capacité par défaut : 10
ArrayList<String> noms = new ArrayList<String>();
// Version simplifiée (diamond operator) — Java 7+
ArrayList<String> noms = new ArrayList<>();
// Avec capacité initiale
ArrayList<String> noms = new ArrayList<>(20);
// À partir d'une autre collection
ArrayList<Integer> nombres = new ArrayList<>(Arrays.asList(1, 2, 3));
Exemple 1 — Déclaration et création
import java.util.ArrayList;
public class Test {
public static void main(String[] args) {
// ArrayList de chaînes de caractères
ArrayList<String> noms = new ArrayList<>();
// ArrayList d'entiers (utilise Integer, pas int)
ArrayList<Integer> notes = new ArrayList<>();
// ArrayList d'objets personnalisés
ArrayList<Etudiant> etudiants = new ArrayList<>();
System.out.println("Liste créée avec succès");
}
}
Le constructeur par défaut crée une ArrayList avec une capacité de 10 éléments. La capacité est le nombre d'éléments qu'elle peut contenir sans avoir à s'agrandir. Si vous savez que vous aurez besoin de plus d'éléments, il est plus efficace de spécifier une capacité initiale plus grande.
3. Méthodes principales
| Méthode | Description | Complexité |
|---|---|---|
boolean add(E e) |
Ajoute un élément à la fin de la liste | O(1) amorti |
void add(int index, E element) |
Insère un élément à une position spécifique | O(n) |
E remove(int index) |
Supprime l'élément à l'index spécifié | O(n) |
boolean remove(Object o) |
Supprime la première occurrence de l'objet | O(n) |
E set(int index, E element) |
Remplace l'élément à l'index spécifié | O(1) |
E get(int index) |
Retourne l'élément à l'index spécifié | O(1) |
int size() |
Retourne le nombre d'éléments | O(1) |
boolean isEmpty() |
Vérifie si la liste est vide | O(1) |
void clear() |
Supprime tous les éléments | O(n) |
boolean contains(Object o) |
Vérifie si un élément existe | O(n) |
int indexOf(Object o) |
Retourne l'index de la première occurrence | O(n) |
4. Ajout d'éléments — add()
Exemple 2 — Ajout d'éléments
import java.util.ArrayList;
public class Test {
public static void main(String[] args) {
ArrayList<Integer> liste = new ArrayList<>();
// Ajout à la fin
liste.add(4);
liste.add(5);
liste.add(2);
System.out.println("Après ajouts : " + liste);
// Insertion à une position spécifique
liste.add(0, 1); // Insère 1 à l'index 0
System.out.println("Après insertion : " + liste);
// Ajout de plusieurs éléments
liste.addAll(Arrays.asList(10, 20, 30));
System.out.println("Après addAll : " + liste);
}
}
Après ajouts : [4, 5, 2] Après insertion : [1, 4, 5, 2] Après addAll : [1, 4, 5, 2, 10, 20, 30]
5. Suppression d'éléments — remove()
Exemple 3 — Suppression d'éléments
import java.util.ArrayList;
public class Test {
public static void main(String[] args) {
ArrayList<String> fruits = new ArrayList<>();
fruits.add("Pomme");
fruits.add("Banane");
fruits.add("Orange");
fruits.add("Pomme");
fruits.add("Kiwi");
System.out.println("Liste originale : " + fruits);
// Suppression par index
fruits.remove(1); // Supprime "Banane"
System.out.println("Après remove(1) : " + fruits);
// Suppression par objet (première occurrence)
fruits.remove("Pomme");
System.out.println("Après remove('Pomme') : " + fruits);
// Suppression de tous les éléments
fruits.clear();
System.out.println("Après clear() : " + fruits);
System.out.println("Est vide ? " + fruits.isEmpty());
}
}
Liste originale : [Pomme, Banane, Orange, Pomme, Kiwi]
Après remove(1) : [Pomme, Orange, Pomme, Kiwi]
Après remove('Pomme') : [Orange, Pomme, Kiwi]
Après clear() : []
Est vide ? true
6. Accès et modification — get() et set()
Exemple 4 — Lecture et modification
import java.util.ArrayList;
public class Test {
public static void main(String[] args) {
ArrayList<Integer> notes = new ArrayList<>();
notes.add(12);
notes.add(15);
notes.add(18);
notes.add(14);
// Accès par get()
System.out.println("Note à l'index 1 : " + notes.get(1));
// Parcours classique
System.out.print("Toutes les notes : ");
for (int i = 0; i < notes.size(); i++) {
System.out.print(notes.get(i) + " ");
}
System.out.println();
// Modification avec set()
notes.set(2, 20); // Remplace 18 par 20
System.out.println("Après modification : " + notes);
}
}
Note à l'index 1 : 15 Toutes les notes : 12 15 18 14 Après modification : [12, 15, 20, 14]
7. Parcours d'une ArrayList
Exemple 5 — Différentes façons de parcourir
import java.util.ArrayList;
import java.util.Iterator;
public class Test {
public static void main(String[] args) {
ArrayList<String> langages = new ArrayList<>();
langages.add("Java");
langages.add("Python");
langages.add("JavaScript");
langages.add("C++");
// 1. Boucle for classique
System.out.println("=== Boucle for classique ===");
for (int i = 0; i < langages.size(); i++) {
System.out.println(langages.get(i));
}
// 2. Boucle for-each (recommandée)
System.out.println("\n=== Boucle for-each ===");
for (String lang : langages) {
System.out.println(lang);
}
// 3. Avec Iterator
System.out.println("\n=== Iterator ===");
Iterator<String> it = langages.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
// 4. Avec forEach() + lambda (Java 8+)
System.out.println("\n=== forEach() avec lambda ===");
langages.forEach(lang -> System.out.println(lang));
}
}
8. Tri d'une ArrayList — Collections.sort()
Exemple 6 — Tri avec Collections.sort()
import java.util.ArrayList;
import java.util.Collections;
public class Test {
public static void main(String[] args) {
ArrayList<Integer> nombres = new ArrayList<>();
nombres.add(4);
nombres.add(5);
nombres.add(2);
nombres.add(9);
nombres.add(1);
System.out.println("Liste non triée : " + nombres);
// Tri en ordre croissant
Collections.sort(nombres);
System.out.println("Liste triée croissant : " + nombres);
// Tri en ordre décroissant
Collections.sort(nombres, Collections.reverseOrder());
System.out.println("Liste triée décroissant : " + nombres);
// Tri personnalisé avec lambda (Java 8+)
ArrayList<String> mots = new ArrayList<>(Arrays.asList("banane", "apple", "cerise", "date"));
mots.sort((a, b) -> a.compareTo(b));
System.out.println("Mots triés : " + mots);
}
}
Liste non triée : [4, 5, 2, 9, 1] Liste triée croissant : [1, 2, 4, 5, 9] Liste triée décroissant : [9, 5, 4, 2, 1] Mots triés : [apple, banane, cerise, date]
9. ArrayList avec objets personnalisés
Exemple 7 — ArrayList d'étudiants
import java.util.ArrayList;
import java.util.Collections;
class Etudiant implements Comparable<Etudiant> {
private String nom;
private double moyenne;
public Etudiant(String nom, double moyenne) {
this.nom = nom;
this.moyenne = moyenne;
}
public String getNom() { return nom; }
public double getMoyenne() { return moyenne; }
@Override
public String toString() {
return String.format("%s (%.2f)", nom, moyenne);
}
@Override
public int compareTo(Etudiant autre) {
return Double.compare(autre.moyenne, this.moyenne); // Tri par moyenne décroissante
}
}
public class Test {
public static void main(String[] args) {
ArrayList<Etudiant> promotion = new ArrayList<>();
promotion.add(new Etudiant("Mostafa", 16.5));
promotion.add(new Etudiant("Amal", 18.0));
promotion.add(new Etudiant("Youssef", 14.5));
promotion.add(new Etudiant("Fatima", 17.2));
System.out.println("=== Liste originale ===");
for (Etudiant e : promotion) {
System.out.println(e);
}
// Tri selon compareTo
Collections.sort(promotion);
System.out.println("\n=== Liste triée par moyenne (décroissante) ===");
for (Etudiant e : promotion) {
System.out.println(e);
}
}
}
=== Liste originale === Mostafa (16.50) Amal (18.00) Youssef (14.50) Fatima (17.20) === Liste triée par moyenne (décroissante) === Amal (18.00) Fatima (17.20) Mostafa (16.50) Youssef (14.50)
10. Tableau comparatif — Array vs ArrayList
| Caractéristique | Array (tableau) | ArrayList |
|---|---|---|
| Taille | Fixe (déterminée à la création) | Dynamique (redimensionnable automatiquement) |
| Types supportés | Primitifs et objets | Objets uniquement (avec autoboxing pour primitifs) |
| Syntaxe d'accès | tableau[index] |
liste.get(index) |
| Syntaxe de modification | tableau[index] = valeur |
liste.set(index, valeur) |
| Ajout d'éléments | Non possible (taille fixe) | add() — dynamique |
| Suppression d'éléments | Non possible (taille fixe) | remove() — décalage automatique |
| Dimension | array.length (attribut) |
list.size() (méthode) |
| Performance | Plus rapide (accès direct) | Légèrement plus lent (méthodes + redimensionnement) |
| Type générique | Non applicable | Oui (ArrayList<E>) |
- Array de primitifs : les valeurs réelles sont stockées dans des emplacements contigus.
- Array d'objets : les références sont stockées dans des emplacements contigus, les objets sont ailleurs.
- ArrayList : fonctionne comme un tableau d'objets — les références sont stockées de façon contiguë, les objets réels sont sur le tas.
11. Conversion entre Array et ArrayList
Exemple 8 — Conversions
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Test {
public static void main(String[] args) {
// Array → ArrayList
String[] tableau = {"A", "B", "C", "D"};
ArrayList<String> liste = new ArrayList<>(Arrays.asList(tableau));
System.out.println("Array → ArrayList : " + liste);
// ArrayList → Array
String[] nouveauTableau = liste.toArray(new String[0]);
System.out.println("ArrayList → Array : " + Arrays.toString(nouveauTableau));
// Version Java 8+ : Stream
int[] nombres = {1, 2, 3, 4, 5};
ArrayList<Integer> listeNombres = Arrays.stream(nombres)
.boxed()
.collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
System.out.println("Primitifs → ArrayList : " + listeNombres);
}
}
Array → ArrayList : [A, B, C, D] ArrayList → Array : [A, B, C, D] Primitifs → ArrayList : [1, 2, 3, 4, 5]
12. Exemple complet — Gestion d'une liste de tâches
Exemple 9 — Application de gestion de tâches
import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;
public class GestionTaches {
private ArrayList<String> taches;
public GestionTaches() {
taches = new ArrayList<>();
}
public void ajouterTache(String tache) {
taches.add(tache);
System.out.println("✓ Tâche ajoutée : " + tache);
}
public void supprimerTache(int index) {
if (index >= 0 && index < taches.size()) {
String supprimee = taches.remove(index);
System.out.println("✗ Tâche supprimée : " + supprimee);
} else {
System.out.println("Index invalide !");
}
}
public void marquerCompletee(int index) {
if (index >= 0 && index < taches.size()) {
String tache = taches.get(index);
taches.set(index, "✓ " + tache);
System.out.println("✓ Tâche complétée : " + tache);
} else {
System.out.println("Index invalide !");
}
}
public void afficherTaches() {
if (taches.isEmpty()) {
System.out.println("Aucune tâche dans la liste.");
return;
}
System.out.println("\n=== LISTE DES TÂCHES ===");
for (int i = 0; i < taches.size(); i++) {
System.out.printf("%d. %s%n", i + 1, taches.get(i));
}
System.out.println("Total : " + taches.size() + " tâche(s)\n");
}
public void trierTaches() {
Collections.sort(taches);
System.out.println("Tâches triées alphabétiquement.");
}
public static void main(String[] args) {
GestionTaches gestion = new GestionTaches();
Scanner scanner = new Scanner(System.in);
int choix;
do {
System.out.println("\n=== MENU ===");
System.out.println("1. Ajouter une tâche");
System.out.println("2. Supprimer une tâche");
System.out.println("3. Marquer une tâche comme complétée");
System.out.println("4. Afficher toutes les tâches");
System.out.println("5. Trier les tâches");
System.out.println("6. Quitter");
System.out.print("Votre choix : ");
choix = scanner.nextInt();
scanner.nextLine(); // Consommer le saut de ligne
switch (choix) {
case 1:
System.out.print("Nom de la tâche : ");
String tache = scanner.nextLine();
gestion.ajouterTache(tache);
break;
case 2:
gestion.afficherTaches();
System.out.print("Numéro de la tâche à supprimer : ");
int indexSuppr = scanner.nextInt() - 1;
gestion.supprimerTache(indexSuppr);
break;
case 3:
gestion.afficherTaches();
System.out.print("Numéro de la tâche à compléter : ");
int indexComplete = scanner.nextInt() - 1;
gestion.marquerCompletee(indexComplete);
break;
case 4:
gestion.afficherTaches();
break;
case 5:
gestion.trierTaches();
break;
case 6:
System.out.println("Au revoir !");
break;
default:
System.out.println("Choix invalide !");
}
} while (choix != 6);
scanner.close();
}
}
13. Exercice
Gestionnaire de contacts
Créer une application de gestion de contacts utilisant ArrayList.
Travail demandé
- Créer une classe
Contactavec les attributs :nom,prenom,telephone,email. - Créer une classe
GestionnaireContactsavec uneArrayList<Contact>. - Implémenter les méthodes :
ajouterContact(Contact c)supprimerContact(int index)modifierContact(int index, Contact nouveau)rechercherParNom(String nom)— retourne tous les contacts dont le nom contient la chaînetrierParNom()— tri alphabétiqueafficherTous()
- Créer un menu console pour tester l'application.
import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;
import java.util.stream.Collectors;
class Contact implements Comparable<Contact> {
private String nom;
private String prenom;
private String telephone;
private String email;
public Contact(String nom, String prenom, String telephone, String email) {
this.nom = nom;
this.prenom = prenom;
this.telephone = telephone;
this.email = email;
}
// Getters
public String getNom() { return nom; }
public String getPrenom() { return prenom; }
public String getTelephone() { return telephone; }
public String getEmail() { return email; }
// Setters
public void setNom(String nom) { this.nom = nom; }
public void setPrenom(String prenom) { this.prenom = prenom; }
public void setTelephone(String telephone) { this.telephone = telephone; }
public void setEmail(String email) { this.email = email; }
@Override
public String toString() {
return String.format("%s %s | Tél: %s | Email: %s",
prenom, nom, telephone, email);
}
@Override
public int compareTo(Contact autre) {
int cmp = this.nom.compareTo(autre.nom);
if (cmp == 0) {
return this.prenom.compareTo(autre.prenom);
}
return cmp;
}
}
class GestionnaireContacts {
private ArrayList<Contact> contacts;
public GestionnaireContacts() {
contacts = new ArrayList<>();
}
public void ajouterContact(Contact c) {
contacts.add(c);
System.out.println("✓ Contact ajouté : " + c.getPrenom() + " " + c.getNom());
}
public boolean supprimerContact(int index) {
if (index >= 0 && index < contacts.size()) {
Contact supprime = contacts.remove(index);
System.out.println("✗ Contact supprimé : " + supprime.getPrenom() + " " + supprime.getNom());
return true;
}
System.out.println("Index invalide !");
return false;
}
public boolean modifierContact(int index, Contact nouveau) {
if (index >= 0 && index < contacts.size()) {
Contact ancien = contacts.set(index, nouveau);
System.out.println("✓ Contact modifié : " + ancien.getPrenom() + " " + ancien.getNom() + " → " + nouveau.getPrenom() + " " + nouveau.getNom());
return true;
}
System.out.println("Index invalide !");
return false;
}
public ArrayList<Contact> rechercherParNom(String recherche) {
return contacts.stream()
.filter(c -> c.getNom().toLowerCase().contains(recherche.toLowerCase()))
.collect(Collectors.toCollection(ArrayList::new));
}
public void trierParNom() {
Collections.sort(contacts);
System.out.println("✓ Contacts triés par nom");
}
public void afficherTous() {
if (contacts.isEmpty()) {
System.out.println("Aucun contact dans l'annuaire.");
return;
}
System.out.println("\n=== ANNUAIRE (" + contacts.size() + " contact(s)) ===");
for (int i = 0; i < contacts.size(); i++) {
System.out.printf("%d. %s%n", i + 1, contacts.get(i));
}
System.out.println();
}
public int getNombre() {
return contacts.size();
}
public Contact getContact(int index) {
if (index >= 0 && index < contacts.size()) {
return contacts.get(index);
}
return null;
}
}
public class TestContacts {
private static Scanner scanner = new Scanner(System.in);
private static GestionnaireContacts gestionnaire = new GestionnaireContacts();
private static Contact saisirContact() {
System.out.print("Nom : ");
String nom = scanner.nextLine();
System.out.print("Prénom : ");
String prenom = scanner.nextLine();
System.out.print("Téléphone : ");
String telephone = scanner.nextLine();
System.out.print("Email : ");
String email = scanner.nextLine();
return new Contact(nom, prenom, telephone, email);
}
public static void main(String[] args) {
int choix;
do {
System.out.println("\n╔════════════════════════════════╗");
System.out.println("║ GESTIONNAIRE DE CONTACTS ║");
System.out.println("╠════════════════════════════════╣");
System.out.println("║ 1. Ajouter un contact ║");
System.out.println("║ 2. Supprimer un contact ║");
System.out.println("║ 3. Modifier un contact ║");
System.out.println("║ 4. Rechercher par nom ║");
System.out.println("║ 5. Trier par nom ║");
System.out.println("║ 6. Afficher tous les contacts ║");
System.out.println("║ 7. Quitter ║");
System.out.println("╚════════════════════════════════╝");
System.out.print("Votre choix : ");
choix = scanner.nextInt();
scanner.nextLine();
switch (choix) {
case 1:
System.out.println("\n--- Ajout d'un contact ---");
gestionnaire.ajouterContact(saisirContact());
break;
case 2:
gestionnaire.afficherTous();
if (gestionnaire.getNombre() > 0) {
System.out.print("Numéro du contact à supprimer : ");
int index = scanner.nextInt() - 1;
gestionnaire.supprimerContact(index);
}
break;
case 3:
gestionnaire.afficherTous();
if (gestionnaire.getNombre() > 0) {
System.out.print("Numéro du contact à modifier : ");
int index = scanner.nextInt() - 1;
scanner.nextLine();
if (gestionnaire.getContact(index) != null) {
System.out.println("--- Nouveaux coordonnées ---");
gestionnaire.modifierContact(index, saisirContact());
} else {
System.out.println("Index invalide !");
}
}
break;
case 4:
System.out.print("Nom à rechercher : ");
String recherche = scanner.nextLine();
ArrayList<Contact> resultats = gestionnaire.rechercherParNom(recherche);
if (resultats.isEmpty()) {
System.out.println("Aucun contact trouvé pour : " + recherche);
} else {
System.out.println("\n--- Résultats (" + resultats.size() + " contact(s)) ---");
for (int i = 0; i < resultats.size(); i++) {
System.out.printf("%d. %s%n", i + 1, resultats.get(i));
}
}
break;
case 5:
gestionnaire.trierParNom();
gestionnaire.afficherTous();
break;
case 6:
gestionnaire.afficherTous();
break;
case 7:
System.out.println("Au revoir !");
break;
default:
System.out.println("Choix invalide !");
}
} while (choix != 7);
}
}
- Génériques :
ArrayList<Contact>garantit la sécurité des types. Comparable: implémenté pour permettre le tri naturel avecCollections.sort().- Streams : utilisation de
stream().filter().collect()pour la recherche. - Encapsulation : les contacts sont gérés via des méthodes dédiées.
L'essentiel en bref
ArrayListest une liste dynamique redimensionnable du Java Collections Framework.- Elle ne peut contenir que des objets (l'autoboxing convertit automatiquement les primitifs).
- Création :
ArrayList<Type> nom = new ArrayList<>(); - Ajout :
add(element)(à la fin) ouadd(index, element)(à une position). - Suppression :
remove(index)ouremove(Object). - Accès :
get(index)— modification :set(index, element). - Taille :
size()(méthode, pas attribut). - Tri :
Collections.sort(liste)(nécessiteComparableouComparator). - Parcours : for-each, for classique, iterator, forEach() avec lambda.
- Différence clé avec les tableaux : taille dynamique, méthodes intégrées, objets uniquement.
ArrayList a été introduite dans Java 1.2 (1998) avec le Java Collections Framework, une refonte majeure des structures de données en Java. Contrairement à Vector (qui existe depuis Java 1.0), ArrayList n'est pas synchronisée, ce qui la rend plus performante pour les applications mono-thread. L'introduction des génériques en Java 5 (2004) a permis de typer ArrayList avec ArrayList<E>, éliminant les casts dangereux. Java 8 a ajouté l'API Stream et les méthodes forEach(), removeIf(), etc. Aujourd'hui, ArrayList est l'une des collections les plus utilisées en Java.
Discussion (0)
Soyez le premier à laisser un commentaire !
Laisser un commentaire
Votre commentaire sera visible après modération.