CodeGym /Corsi /JAVA 25 SELF /Map.copyOf, Set.copyOf e altre utility

Map.copyOf, Set.copyOf e altre utility

JAVA 25 SELF
Livello 34, Lezione 1
Disponibile

1. Metodi copyOf: List.copyOf, Set.copyOf, Map.copyOf

Immaginate una situazione: esiste un metodo che deve restituire una lista, un insieme o una mappa, ma è importante che il codice chiamante non possa in alcun modo modificare il contenuto di quella collezione. Ad esempio, «elenco delle valute supportate» o «insieme dei ruoli dell'utente». Qualsiasi inserimento/eliminazione accidentale può compromettere la logica di business.

Fino a Java 10 si doveva o restituire una copia della collezione manualmente, oppure usare wrapper come Collections.unmodifiableList(list). Il wrapper protegge solo dalle modifiche effettuate attraverso se stesso, ma non dalle modifiche della collezione originale.

Ora abbiamo un modo più affidabile — i metodi copyOf.

Che cosa sono?

I metodi List.copyOf(Collection), Set.copyOf(Collection), Map.copyOf(Map) (Java 10) creano una vera copia immutabile della collezione o mappa passata.

  • La copia non è collegata alla collezione originale: le modifiche all'originale non influiscono sul risultato copyOf.
  • Modificare la copia è impossibile: qualsiasi tentativo di modifica genera UnsupportedOperationException.

Esempio di creazione di una copia immutabile

import java.util.*;

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

        // Creiamo una copia immutabile
        List<String> immutable = List.copyOf(modifiable);

        // Proviamo a modificare la copia
        try {
            immutable.add("C++"); // Solleverà UnsupportedOperationException
        } catch (UnsupportedOperationException e) {
            System.out.println("Impossibile aggiungere un elemento a una collezione immutabile!");
        }

        // Modifichiamo la lista originale
        modifiable.add("Kotlin");

        // La copia è rimasta invariata!
        System.out.println("Lista originale: " + modifiable);
        System.out.println("Copia immutabile: " + immutable);
    }
}

Output del programma:

Impossibile aggiungere un elemento a una collezione immutabile!
Lista originale: [Java, Python, Kotlin]
Copia immutabile: [Java, Python]

Sintesi di ciascun metodo

  • List.copyOf(Collection) — restituisce una lista immutabile con gli elementi della collezione originale.
  • Set.copyOf(Collection) — restituisce un insieme immutabile con gli elementi della collezione; i duplicati verranno eliminati.
  • Map.copyOf(Map) — restituisce una mappa immutabile con le coppie della mappa originale.

Esempio con Set e 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);

        // Proviamo ad aggiungere un elemento
        try {
            immutableSet.add("D");
        } catch (UnsupportedOperationException e) {
            System.out.println("Impossibile modificare 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("Impossibile modificare Map!");
        }
    }
}

2. Caratteristiche e limitazioni dei metodi copyOf

Gli elementi null non sono ammessi

Come i metodi factory List.of, Set.of, Map.of, i metodi copyOf vietano null come elemento, chiave o valore. Se nella collezione/mappa di origine è presente null, durante la copia verrà sollevata NullPointerException.

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

La collezione è davvero immutabile

Qualsiasi tentativo di add/remove/put/replace comporta UnsupportedOperationException.

Originale e copia non sono collegati

Le modifiche alla collezione originale non influiscono sulla copia, e viceversa.

Se la collezione è già immutabile — viene restituita la stessa istanza

Se passate una collezione già immutabile (per esempio il risultato List.of(...)) — copyOf restituirà lo stesso oggetto (risparmio di memoria).

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

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

L'implementazione concreta non è garantita

Il tipo della collezione restituita è semplicemente List, Set o Map. Non è necessariamente ArrayList, HashSet o HashMap. Non fate affidamento sui dettagli di implementazione (per esempio, tipo interno e ottimizzazioni); il contratto è l'immutabilità e l'interfaccia corrispondente.

3. Differenza tra copyOf e i wrapper non modificabili (unmodifiable wrappers)

Collections.unmodifiableList(list) crea un wrapper sopra una collezione esistente. Se la collezione originale viene modificata, queste modifiche si vedranno anche nel wrapper.

List.copyOf(list) crea una nuova collezione immutabile, non collegata all'originale.

Dimostrazione della differenza

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);

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

        // Modifichiamo l'originale
        original.add("C");

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

Output:

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

Il wrapper riflette le modifiche dell'originale, mentre la copia rimane invariata.

4. Casi d'uso pratici di copyOf

Protezione dei dati al ritorno da un metodo

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

    public List<String> getSupportedCurrencies() {
        // Nessuno potrà modificare il risultato
        return List.copyOf(currencies);
    }
}

Ora il codice chiamante non potrà aggiungere o rimuovere una valuta dall'elenco restituito.

Passaggio tra i livelli dell'applicazione

Quando i dati vengono passati tra i livelli (DAO → servizio → controller), utilizzate copyOf per essere certi che nessuno modificherà la collezione «per strada».

Pubblicazione sicura nei programmi multithread

Le collezioni immutabili sono un modo comodo per «condividere» i dati tra thread in modo sicuro senza sincronizzazione aggiuntiva.

5. Errori tipici nell'uso di copyOf e delle collezioni immutabili

Errore n. 1: tentativo di inserire null. I metodi copyOf (così come of) non tollerano null — né come elemento di lista/insieme, né come chiave/valore di mappa. Durante la copia otterrete NullPointerException.

Errore n. 2: confusione tra wrapper e copia. copyOf crea una copia indipendente: le modifiche dell'originale non sono visibili nella copia. Invece Collections.unmodifiableList(list) si limita ad avvolgere la collezione originale: tutte le modifiche dell'originale si rifletteranno nel wrapper.

Errore n. 3: tentativo di modificare una collezione immutabile. Le chiamate add/remove/put sulle collezioni create con copyOf/of generano UnsupportedOperationException.

Errore n. 4: dimenticare i limiti dei metodi factory per le mappe. Per esempio, Map.of() supporta fino a 10 coppie chiave–valore. Se ne servono di più — utilizzate Map.ofEntries(...) oppure costruite una mappa modificabile e poi applicate Map.copyOf.

Errore n. 5: fare affidamento su un'implementazione concreta. Non aspettatevi che copyOf restituisca proprio ArrayList o HashSet. Sono garantiti solo l'interfaccia (List/Set/Map) e l'immutabilità.

1
Compito
JAVA 25 SELF, livello 34, lezione 1
Bloccato
Carrello del negozio: vista dal vivo contro istantanea 🛒
Carrello del negozio: vista dal vivo contro istantanea 🛒
1
Compito
JAVA 25 SELF, livello 34, lezione 1
Bloccato
Configurazione del gioco: fissiamo le impostazioni di rilascio 🎮
Configurazione del gioco: fissiamo le impostazioni di rilascio 🎮
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION