CodeGym /Cours /JAVA 25 SELF /Collections mutables vs immuables : différences et usages...

Collections mutables vs immuables : différences et usages

JAVA 25 SELF
Niveau 34 , Leçon 3
Disponible

1. Introduction

Pour faire simple, une collection mutable, c’est une collection que l’on peut modifier après sa création : ajouter, supprimer et changer des éléments. Une collection immutable (immuable) est une collection que l’on ne peut plus modifier après sa création. Comme du béton une fois durci : on peut regarder et toucher, mais on ne peut plus « modeler » de nouvelles formes.

Une collection mutable, c’est un carnet et un crayon : on écrit, on efface, on ajoute de nouvelles notes. Une collection immuable, c’est une page plastifiée : plus personne ne peut rien y ajouter ni y effacer.

Exemples de collections mutables

En Java, la quasi-totalité des collections standard sont mutables par défaut. Par exemple :

  • ArrayList
  • LinkedList
  • HashSet
  • TreeSet
  • HashMap
  • LinkedHashMap
  • et bien d’autres

Exemple : ArrayList

import java.util.*;

List<String> names = new ArrayList<>();
names.add("Alice");
names.add("Bob");
names.set(1, "Charlie"); // remplace Bob par Charlie
names.remove("Alice");   // supprime Alice
System.out.println(names); // [Charlie]

Ici, nous pouvons tout faire avec la collection : ajouter, supprimer, échanger des éléments. C’est pratique quand la collection se construit dynamiquement, par exemple lors de la lecture d’un fichier ou d’une saisie utilisateur.

2. Exemples de collections immuables

Introduites avec Java 9, vous les avez sans doute déjà croisées, mais il faut encore s’y habituer :

  • List.of(...)
  • Set.of(...)
  • Map.of(...)
  • List.copyOf(collection)
  • Set.copyOf(collection)
  • Map.copyOf(map)

Exemple : List.of

List<String> planets = List.of("Mercury", "Venus", "Earth", "Mars");
System.out.println(planets); // [Mercury, Venus, Earth, Mars]
planets.add("Jupiter"); // Lève UnsupportedOperationException !

Toute tentative de modifier la collection déclenche une exception à l’exécution.

Exemple : Collections.unmodifiableList

List<String> modifiable = new ArrayList<>(List.of("a", "b"));
List<String> unmodifiable = Collections.unmodifiableList(modifiable);
unmodifiable.add("c"); // UnsupportedOperationException!

Mais il y a un piège : si vous modifiez la collection source, le wrapper change aussi !

modifiable.add("c");
System.out.println(unmodifiable); // [a, b, c] — l’élément est apparu !

3. Principales différences entre collections mutables et immuables

Propriété Mutables Immuables
Peut-on ajouter un élément ? Oui Non
Peut-on supprimer un élément ? Oui Non
Peut-on modifier un élément ? Oui (par ex. set) Non
Sécurité vis-à-vis des threads Non (par défaut) Oui (pas d’état — rien à modifier)
Peut-on ajouter null ? Oui (généralement) Non (dans les méthodes factory de Java 9+)
Implémentation ArrayList, HashSet, etc. List.of, Set.of, Map.of, copyOf

4. Pourquoi a-t-on besoin de collections immuables ?

Question naturelle : si les collections mutables sont si flexibles, pourquoi des immuables ? Les raisons sont nombreuses et touchent à la sécurité, à la lisibilité et à la prédictibilité du code.

Sécurité et prévention des erreurs

Lorsque vous exposez une collection (par exemple depuis une méthode ou une classe), vous voulez être sûr que personne ne va en modifier le contenu par inadvertance. C’est particulièrement important si la collection contient des données « importantes » qui ne doivent pas bouger après l’initialisation.

Exemple :

public class Team {
    private final List<String> players;

    public Team(List<String> players) {
        // On crée une copie immuable pour que personne ne puisse modifier la composition
        this.players = List.copyOf(players);
    }

    public List<String> getPlayers() {
        return players;
    }
}

Désormais, tout code qui reçoit la liste des joueurs ne pourra pas y ajouter son « ami ».

Sécurité vis-à-vis des threads

Les collections mutables ne sont pas sûres lorsqu’elles sont consultées depuis plusieurs threads simultanément. À l’inverse, les collections immuables peuvent être partagées librement entre threads — personne ne pourra les altérer.

Débogage facilité

Si la collection ne change pas, vous savez toujours ce qu’elle contient. Pas besoin de craindre qu’elle ait été modifiée « en douce » ailleurs dans le code.

Utilisation comme clés ou valeurs dans d’autres collections

Les objets immuables sont des candidats idéaux comme clés dans une Map ou comme éléments d’un Set. Si un objet peut changer après son insertion, vous risquez d’en perdre l’accès (voir hashCode et equals).

5. Quand utiliser des collections mutables ?

Les collections mutables sont indiquées lorsque :

  • La collection est construite par étapes, dans une boucle ou à partir de sources multiples.
  • Des modifications fréquentes sont nécessaires : ajout, suppression, tri.
  • La collection est à usage interne et aucun code « externe » ne peut l’altérer.

Exemple : construction d’une liste

List<String> shoppingList = new ArrayList<>();
shoppingList.add("Lait");
shoppingList.add("Pain");
shoppingList.add("Pommes");
// Après la construction, on peut en faire une version immuable
List<String> finalList = List.copyOf(shoppingList);

6. Quand utiliser des collections immuables ?

  • Pour stocker des données constantes (par ex. la liste des jours de la semaine).
  • Pour transmettre des collections entre couches de l’application (par ex. du DAO au service).
  • Pour retourner des collections depuis des méthodes afin de les protéger des modifications.
  • Pour des scénarios multithreads où la sécurité est importante.

Exemple : données constantes

public static final List<String> WEEKDAYS = List.of(
    "Monday", "Tuesday", "Wednesday", "Thursday", "Friday"
);

Exemple : exposition vers l’extérieur

public List<String> getReadOnlyNames() {
    return List.copyOf(names); // personne ne pourra modifier la liste
}

7. Particularités et pièges

Immuabilité ≠ sécurité vis-à-vis des threads

Une collection immuable est protégée contre les modifications, mais cela ne signifie pas qu’elle est à l’abri de tous les problèmes en environnement multithread (par exemple si les éléments de la collection sont eux-mêmes mutables).

List<List<String>> listOfLists = List.of(new ArrayList<>());
listOfLists.get(0).add("Oops!"); // On peut modifier la liste interne !

Wrappers vs copies

Comme mentionné plus haut, Collections.unmodifiableList est un wrapper : si la collection source change, le wrapper change aussi. En revanche, List.copyOf crée une véritable copie indépendante.

List<String> base = new ArrayList<>(List.of("a", "b"));
List<String> wrap = Collections.unmodifiableList(base);
List<String> copy = List.copyOf(base);

base.add("c");
System.out.println(wrap); // [a, b, c] — a changé !
System.out.println(copy); // [a, b] — inchangé !

NullPointerException

Les méthodes factory (List.of, Set.of, Map.of) n’autorisent pas l’ajout de null :

List<String> bad = List.of("a", null); // Lève NullPointerException dès la création !

8. Comparaison des approches : avantages et inconvénients

Collections mutables

Le principal atout des collections mutables est leur flexibilité. Vous pouvez ajouter et supprimer des éléments à la volée, restructurer la collection au fil de l’évolution de la logique du programme. Cette approche est particulièrement pratique lorsqu’il faut assembler rapidement une structure temporaire ou effectuer des modifications dynamiques.

Mais cette commodité a un coût. Une collection mutable comporte toujours un risque d’intervention accidentelle : quelqu’un dans le code peut modifier les données par mégarde, entraînant des bugs difficiles à détecter. Dans les programmes multithreads, c’est encore pire — des modifications parallèles conduisent facilement à des conditions de concurrence et à des défaillances inattendues. Le cycle de vie de ces données est aussi plus difficile à contrôler : il faut constamment se souvenir qui et quand peut modifier la collection.

Collections immuables

Avec les collections immuables, on travaille plus sereinement. Vous savez exactement que personne ne les « corrigera » dans votre dos. Cela rend le code plus sûr, plus facile à déboguer et à tester, et ces collections se transmettent aisément entre threads sans verrous supplémentaires.

L’inconvénient, c’est qu’il faut parfois sacrifier un peu de performance. Pour ajouter un nouvel élément, il faut créer une nouvelle copie de la collection, ce qui implique un coût mémoire et temps supplémentaire. De plus, construire de grandes structures directement en immuable peut être peu pratique. En général, on les assemble d’abord dans une collection mutable temporaire, puis on les « fige » quand tout est prêt.

9. Erreurs typiques

Erreur n° 1 : Retourner une collection mutable vers l’extérieur. Si vous retournez depuis une méthode un ArrayList ordinaire, n’importe quel code externe peut ajouter ou supprimer des éléments. Cela peut conduire à des bugs très difficiles à retracer.

Erreur n° 2 : Utiliser un wrapper au lieu d’une copie. Si vous utilisez Collections.unmodifiableList mais que la collection d’origine est modifiée ailleurs, l’« immuabilité » n’est qu’une illusion.

Erreur n° 3 : Objets mutables à l’intérieur de collections immuables. Même si la collection est immuable, ses éléments peuvent être mutables. Cela peut entraîner des changements d’état inattendus.

Erreur n° 4 : Essayer d’ajouter null dans une collection créée via des méthodes factory. Contrairement aux anciennes collections, les nouvelles méthodes factory n’autorisent pas null — vous aurez une NullPointerException.

Erreur n° 5 : S’attendre à une implémentation concrète. Les collections créées via List.of ou Set.of ne garantissent pas le type d’implémentation (ce n’est pas nécessairement ArrayList ou HashSet). Ne vous y fiez pas.

1
Mission
JAVA 25 SELF, niveau 34, leçon 3
Bloqué
Inventaire des animaux : vue en direct ou instantané statique ? 🐾
Inventaire des animaux : vue en direct ou instantané statique ? 🐾
1
Mission
JAVA 25 SELF, niveau 34, leçon 3
Bloqué
Playlists: la collection est immuable, mais les chansons à l'intérieur changent 🎶
Playlists: la collection est immuable, mais les chansons à l'intérieur changent 🎶
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION