CodeGym /Cours /JAVA 25 SELF /Map.copyOf, Set.copyOf et autres utilitaires

Map.copyOf, Set.copyOf et autres utilitaires

JAVA 25 SELF
Niveau 34 , Leçon 1
Disponible

1. Méthodes copyOf : List.copyOf, Set.copyOf, Map.copyOf

Imaginez la situation suivante : une méthode doit renvoyer une liste, un ensemble ou une map, mais il est important que le code appelant ne puisse en aucune façon modifier le contenu de cette collection. Par exemple, « liste des devises prises en charge » ou « ensemble des rôles de l’utilisateur ». Toute insertion/suppression accidentelle peut rompre la logique métier.

Avant Java 10, il fallait soit retourner une copie de la collection manuellement, soit utiliser des wrappers comme Collections.unmodifiableList(list). Le wrapper protège seulement des modifications via lui-même, mais pas des modifications de la collection d’origine.

Nous disposons désormais d’un moyen plus fiable — les méthodes copyOf.

Qu’est-ce que c’est ?

Les méthodes List.copyOf(Collection), Set.copyOf(Collection), Map.copyOf(Map) (Java 10) créent une véritable copie immuable de la collection ou de la map passée.

  • La copie n’est pas liée à la collection d’origine : les modifications de l’original n’affectent pas le résultat de copyOf.
  • Modifier la copie est impossible : toute tentative de modification entraînera une UnsupportedOperationException.

Exemple de création d’une copie immuable

import java.util.*;

public class CopyOfDemo {
    public static void main(String[] args) {
        List<String> modifiable = new ArrayList<>();
        modifiable.add("Java");
        modifiable.add("Python");

        // Création d'une copie immuable
        List<String> immutable = List.copyOf(modifiable);

        // Essayons de modifier la copie
        try {
            immutable.add("C++"); // Déclenchera UnsupportedOperationException
        } catch (UnsupportedOperationException e) {
            System.out.println("Impossible d'ajouter un élément à une collection immuable !");
        }

        // Modification de la liste d'origine
        modifiable.add("Kotlin");

        // La copie est restée inchangée !
        System.out.println("Liste d'origine: " + modifiable);
        System.out.println("Copie immuable: " + immutable);
    }
}

Sortie du programme :

Impossible d'ajouter un élément à une collection immuable !
Liste d'origine: [Java, Python, Kotlin]
Copie immuable: [Java, Python]

Bref aperçu de chaque méthode

  • List.copyOf(Collection) — renvoie une liste immuable avec les éléments de la collection d’origine.
  • Set.copyOf(Collection) — renvoie un ensemble immuable avec les éléments de la collection ; les doublons seront supprimés.
  • Map.copyOf(Map) — renvoie une map immuable avec les paires de la map d’origine.

Exemple avec Set et Map

import java.util.*;

public class CopyOfSetMapDemo {
    public static void main(String[] args) {
        Set<String> modifiableSet = new HashSet<>(Set.of("A", "B", "C"));
        Set<String> immutableSet = Set.copyOf(modifiableSet);

        // Essayons d'ajouter un élément
        try {
            immutableSet.add("D");
        } catch (UnsupportedOperationException e) {
            System.out.println("Impossible de modifier le Set !");
        }

        Map<String, Integer> modifiableMap = new HashMap<>();
        modifiableMap.put("Alice", 30);
        modifiableMap.put("Bob", 25);

        Map<String, Integer> immutableMap = Map.copyOf(modifiableMap);

        try {
            immutableMap.put("Charlie", 28);
        } catch (UnsupportedOperationException e) {
            System.out.println("Impossible de modifier la Map !");
        }
    }
}

2. Particularités et limitations des méthodes copyOf

Les éléments null ne sont pas autorisés

Comme les méthodes factory List.of, Set.of, Map.of, les méthodes copyOf interdisent null comme élément, clé ou valeur. S’il y a un null dans la collection/map d’origine, une NullPointerException sera levée lors de la copie.

List<String> listWithNull = Arrays.asList("A", null, "B");
List<String> immutable = List.copyOf(listWithNull); // Déclenchera NullPointerException !

La collection est réellement immuable

Toute tentative de add/remove/put/replace entraîne une UnsupportedOperationException.

L’original et la copie ne sont pas liés

Les modifications de la collection d’origine n’affectent pas la copie, et inversement.

Si la collection est déjà immuable — le même objet est renvoyé

Si vous passez une collection déjà immuable (par exemple, le résultat de List.of(...)) — copyOf renverra le même objet (économie de mémoire).

List<String> immutable = List.of("X", "Y");
List<String> copy = List.copyOf(immutable);

System.out.println(immutable == copy); // true

Aucune implémentation concrète n’est garantie

Le type de la collection renvoyée est simplement List, Set ou Map. Ce n’est pas nécessairement ArrayList, HashSet ou HashMap. Ne vous fiez pas aux détails d’implémentation (par exemple, le type interne et les optimisations) ; le contrat est l’immuabilité et l’interface correspondante.

3. Différence entre copyOf et les wrappers (unmodifiable wrappers)

Collections.unmodifiableList(list) crée un wrapper par-dessus une collection existante. Si la collection d’origine est modifiée, ces modifications sont visibles dans le wrapper.

List.copyOf(list) crée une nouvelle collection immuable, indépendante de l’original.

Démonstration de la différence

import java.util.*;

public class WrapperVsCopyOf {
    public static void main(String[] args) {
        List<String> original = new ArrayList<>(List.of("A", "B"));

        // Wrapper
        List<String> wrapper = Collections.unmodifiableList(original);

        // Copie
        List<String> copy = List.copyOf(original);

        // Modifions l'original
        original.add("C");

        System.out.println("Wrapper: " + wrapper); // [A, B, C]
        System.out.println("Copie: " + copy);      // [A, B]
    }
}

Sortie :

Wrapper: [A, B, C]
Copie: [A, B]

Le wrapper reflète les modifications de l’original, alors que la copie reste inchangée.

4. Scénarios pratiques d’utilisation de copyOf

Protection des données lors du retour d’une méthode

public class CurrencyService {
    private final List<String> currencies = new ArrayList<>(List.of("USD", "EUR", "JPY"));

    public List<String> getSupportedCurrencies() {
        // Personne ne pourra modifier le résultat
        return List.copyOf(currencies);
    }
}

Désormais, le code appelant ne pourra pas ajouter ni supprimer une devise de la liste renvoyée.

Transmission entre couches de l’application

Lorsque les données sont transmises entre les couches (DAO → service → contrôleur), utilisez copyOf pour être sûr que personne ne modifie la collection en chemin.

Publication sûre dans des programmes multithread

Les collections immuables sont un moyen pratique de partager des données entre threads sans synchronisation supplémentaire.

5. Erreurs courantes avec copyOf et les collections immuables

Erreur n° 1 : tentative d’insérer null. Les méthodes copyOf (comme of) n’acceptent pas null — que ce soit comme élément de liste/ensemble ou comme clé/valeur de map. À la copie, vous obtiendrez une NullPointerException.

Erreur n° 2 : confusion entre wrapper et copie. copyOf crée une copie indépendante : les modifications de l’original ne sont pas visibles dans la copie. En revanche, Collections.unmodifiableList(list) ne fait qu’envelopper la collection d’origine : toutes les modifications de l’original seront reflétées dans le wrapper.

Erreur n° 3 : tentative de modifier une collection immuable. Les appels à add/remove/put sur les collections issues de copyOf/of entraînent une UnsupportedOperationException.

Erreur n° 4 : oublier les limites des méthodes factory des maps. Par exemple, Map.of() prend en charge jusqu’à 10 paires clé–valeur. Si vous en avez besoin de plus — utilisez Map.ofEntries(...) ou construisez une map mutable puis appliquez Map.copyOf.

Erreur n° 5 : se fier à une implémentation concrète. N’attendez pas que copyOf renvoie un ArrayList ou un HashSet précis. Seuls l’interface (List/Set/Map) et le caractère immuable sont garantis.

1
Mission
JAVA 25 SELF, niveau 34, leçon 1
Bloqué
Panier du magasin : vue en direct contre instantané 🛒
Panier du magasin : vue en direct contre instantané 🛒
1
Mission
JAVA 25 SELF, niveau 34, leçon 1
Bloqué
Configuration du jeu : figer les paramètres de la version de publication 🎮
Configuration du jeu : figer les paramètres de la version de publication 🎮
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION