CodeGym /Corsi /JAVA 25 SELF /Serializzazione delle collezioni: List, Map, Set

Serializzazione delle collezioni: List, Map, Set

JAVA 25 SELF
Livello 42, Lezione 4
Disponibile

1. Serializzazione delle collezioni

Buona notizia: quasi tutte le collezioni standard di Java (per esempio, ArrayList, HashSet, HashMap e simili) implementano già Serializable. Questo significa che puoi serializzarle subito, senza troppe complicazioni.

Esempio:

import java.io.Serializable;
import java.util.ArrayList;

public class MyList extends ArrayList<String> implements Serializable {
    // Si può anche non scrivere nulla — ArrayList è già Serializable!
}

Nella pratica di solito si serializzano le collezioni standard e tutto funziona senza inutili complicazioni.

Come serializzare una collezione?

Per serializzare una collezione si usa lo stesso approccio che per qualsiasi altro oggetto:

  • Creiamo la collezione.
  • La scriviamo su file tramite ObjectOutputStream.
  • La rileggiamo tramite ObjectInputStream.

Esempio 1: Serializzazione ArrayList<String>

import java.io.*;
import java.util.*;

public class SerializeListDemo {
    public static void main(String[] args) throws Exception {
        // 1. Creiamo una lista di stringhe
        List<String> books = new ArrayList<>();
        books.add("Il giovane Holden");
        books.add("Grandi speranze");
        books.add("Divina Commedia");

        // 2. Salviamo la lista su file
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("books.ser"));
        out.writeObject(books);
        out.close();

        // 3. Rileggiamo la lista dal file
        ObjectInputStream in = new ObjectInputStream(new FileInputStream("books.ser"));
        List<String> loadedBooks = (List<String>) in.readObject();
        in.close();

        // 4. Verifichiamo il risultato
        System.out.println("Elenco dei libri dopo la deserializzazione:");
        for (String book : loadedBooks) {
            System.out.println("- " + book);
        }
    }
}

Output:

Elenco dei libri dopo la deserializzazione:
- Il giovane Holden
- Grandi speranze
- Divina Commedia

Esempio 2: Serializzazione HashSet<Integer>

Set<Integer> numbers = new HashSet<>(Arrays.asList(10, 20, 30, 40));
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("numbers.ser"));
out.writeObject(numbers);
out.close();

ObjectInputStream in = new ObjectInputStream(new FileInputStream("numbers.ser"));
Set<Integer> loadedNumbers = (Set<Integer>) in.readObject();
in.close();

System.out.println("Insieme dopo la deserializzazione: " + loadedNumbers);

Esempio 3: Serializzazione HashMap<String, Integer>

Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 100);
scores.put("Bob", 80);

ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("scores.ser"));
out.writeObject(scores);
out.close();

ObjectInputStream in = new ObjectInputStream(new FileInputStream("scores.ser"));
Map<String, Integer> loadedScores = (Map<String, Integer>) in.readObject();
in.close();

System.out.println("Mappa dopo la deserializzazione: " + loadedScores);

Punti importanti

L’ordine viene mantenuto?

  • Per List (ad esempio, ArrayList) l’ordine degli elementi è sempre preservato.
  • Per Set (HashSet) l’ordine non è garantito (sia prima sia dopo la serializzazione).
  • Per Map (HashMap) l’ordine delle coppie chiave-valore non è garantito (se serve l’ordine — usa LinkedHashMap).

Le collezioni vuote si serializzano e deserializzano senza problemi. Dopo la deserializzazione otterrai una lista/insieme/mappa vuota.

Le collezioni annidate (ad esempio, List<List<String>>) si serializzano correttamente se tutti gli elementi annidati sono serializzabili.

2. Requisiti per gli elementi della collezione

Qui spesso si nasconde la prima trappola seria!

Tutti gli elementi della collezione devono essere a loro volta serializzabili.

Se anche solo un elemento della collezione non implementa l’interfaccia Serializable, la serializzazione della collezione terminerà con l’errore NotSerializableException. E se la collezione è grande e l’errore è da qualche parte all’interno, trovare il colpevole può diventare una caccia al tesoro.

Esempio: serializzazione di una collezione con un oggetto non serializzabile

import java.io.*;
import java.util.*;

class NotSerializableClass {
    int value;
    public NotSerializableClass(int value) { 
        this.value = value; 
    }
}

public class NotSerializableDemo {
    public static void main(String[] args) throws Exception {
        List<Object> list = new ArrayList<>();
        list.add("Hello");
        list.add(new NotSerializableClass(123)); // <- Ops!

        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("badlist.ser"));
        try {
            out.writeObject(list); // Qui verrà lanciata un'eccezione!
        } catch (NotSerializableException e) {
            System.out.println("Errore di serializzazione: " + e);
        }
        out.close();
    }
}

Risultato:

Errore di serializzazione: java.io.NotSerializableException: NotSerializableClass

Che fare?

La soluzione è semplice: tutti gli elementi della collezione devono essere o tipi standard, come String o Integer, oppure tue classi che implementano l’interfaccia Serializable. Se una classe non è serializzabile, è sufficiente aggiungere implements Serializable e il problema si risolve.

3. Peculiarità della serializzazione delle diverse collezioni

L’ordine degli elementi viene mantenuto?

  • List: Sì, l’ordine degli elementi è preservato.
  • Set: Dipende dall’implementazione. In HashSet l’ordine non è garantito, mentre in LinkedHashSet è preservato.
  • Map: In HashMap l’ordine non è garantito, in LinkedHashMap è preservato l’ordine di inserimento.

Dimostrazione:

List<String> list = Arrays.asList("A", "B", "C");
Set<String> set = new HashSet<>(list);

ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("coll.ser"));
out.writeObject(list);
out.writeObject(set);
out.close();

ObjectInputStream in = new ObjectInputStream(new FileInputStream("coll.ser"));
List<String> loadedList = (List<String>) in.readObject();
Set<String> loadedSet = (Set<String>) in.readObject();
in.close();

System.out.println("List: " + loadedList); // sempre [A, B, C]
System.out.println("Set: " + loadedSet);   // può essere [A, C, B], ecc.

Serializzazione di collezioni vuote

Le collezioni vuote si serializzano senza problemi. Dopo la deserializzazione otterrai un oggetto vuoto del tipo richiesto.

Serializzazione di collezioni annidate

Si possono serializzare collezioni che contengono altre collezioni:

List<List<String>> table = new ArrayList<>();
table.add(Arrays.asList("row1-col1", "row1-col2"));
table.add(Arrays.asList("row2-col1", "row2-col2"));

// Serializzazione
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("table.ser"));
out.writeObject(table);
out.close();

// Deserializzazione
ObjectInputStream in = new ObjectInputStream(new FileInputStream("table.ser"));
List<List<String>> loadedTable = (List<List<String>>) in.readObject();
in.close();

System.out.println(loadedTable);

4. Esempio pratico: serializzazione di una collezione di oggetti di una classe propria

Scriviamo insieme una piccola applicazione per una «biblioteca virtuale», in cui serializzeremo un elenco di libri. La classe Book deve essere serializzabile!

import java.io.*;
import java.util.*;

class Book implements Serializable {
    private static final long serialVersionUID = 1L; // per la compatibilità tra versioni della classe
    String title;
    String author;
    int year;

    public Book(String title, String author, int year) {
        this.title = title;
        this.author = author;
        this.year = year;
    }

    @Override
    public String toString() {
        return title + " (" + author + ", " + year + ")";
    }
}

public class LibraryApp {
    public static void main(String[] args) throws Exception {
        List<Book> books = new ArrayList<>();
        books.add(new Book("Il giovane Holden", "J. D. Salinger", 1951));
        books.add(new Book("Grandi speranze", "Charles Dickens", 1861));
        books.add(new Book("Divina Commedia", "Dante Alighieri", 1320));

        // Salviamo la lista su file
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("mylibrary.ser"));
        out.writeObject(books);
        out.close();

        // Rileggiamo la lista
        ObjectInputStream in = new ObjectInputStream(new FileInputStream("mylibrary.ser"));
        List<Book> loadedBooks = (List<Book>) in.readObject();
        in.close();

        System.out.println("Libri dal file:");
        for (Book b : loadedBooks) {
            System.out.println("- " + b);
        }
    }
}

5. Errori tipici nella serializzazione delle collezioni

Errore n. 1: NotSerializableException su un elemento della collezione. Se anche un solo elemento della collezione non è serializzabile, la serializzazione «salterà» con l’errore NotSerializableException. Ad esempio, se hai aggiunto per sbaglio alla collezione un oggetto che non implementa Serializable, o hai dimenticato di aggiungere questa interfaccia alla tua classe.

Errore n. 2: Modifica della classe tra serializzazione e deserializzazione. Se hai serializzato una collezione di oggetti e poi hai cambiato la struttura della classe (ad esempio, aggiunto o rimosso campi), durante la deserializzazione può verificarsi un’eccezione InvalidClassException. Per evitarlo, usa il campo serialVersionUID nella classe.

Errore n. 3: Serializzazione di una collezione con campi transient o static. I campi contrassegnati come transient o static non vengono serializzati. Se i tuoi oggetti dipendono da tali campi, dopo la deserializzazione avranno i valori predefiniti (ad esempio, null o 0).

Errore n. 4: Serializzazione di collezioni con oggetti annidati non serializzabili. Se nella collezione ci sono collezioni annidate o oggetti che non implementano Serializable, l’errore emergerà al livello più profondo — non è sempre immediato capire dove cercare il problema. Controlla tutti i livelli di annidamento!

Errore n. 5: Prestazioni con collezioni molto grandi. Se la collezione è molto grande, la serializzazione può richiedere molto tempo e spazio su disco. In questi casi conviene considerare la serializzazione in streaming o la suddivisione della collezione in parti.

1
Compito
JAVA 25 SELF, livello 42, lezione 4
Bloccato
Serializzazione di una lista di stringhe
Serializzazione di una lista di stringhe
1
Compito
JAVA 25 SELF, livello 42, lezione 4
Bloccato
Serializzazione della mappa dei voti
Serializzazione della mappa dei voti
1
Sondaggio/quiz
Serializzazione, livello 42, lezione 4
Non disponibile
Serializzazione
Introduzione alla serializzazione degli oggetti
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION