CodeGym /Cours /JAVA 25 SELF /Sérialisation des collections : List, Map, Set

Sérialisation des collections : List, Map, Set

JAVA 25 SELF
Niveau 42 , Leçon 4
Disponible

1. Sérialisation des collections

Bonne nouvelle : presque toutes les collections standard de Java (par exemple, ArrayList, HashSet, HashMap et consorts) implémentent déjà Serializable. Cela signifie que vous pouvez les sérialiser telles quelles, sans prise de tête.

Exemple :

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

public class MyList extends ArrayList<String> implements Serializable {
    // On peut même ne rien écrire — ArrayList est déjà Serializable !
}

En pratique, vous sérialisez généralement des collections standard, et tout fonctionne sans complications inutiles.

Comment sérialiser une collection ?

Pour sérialiser une collection, on utilise la même approche que pour n’importe quel autre objet :

  • Créer une collection.
  • L’écrire dans un fichier via ObjectOutputStream.
  • La lire via ObjectInputStream.

Exemple 1 : sérialisation ArrayList<String>

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

public class SerializeListDemo {
    public static void main(String[] args) throws Exception {
        // 1. Créer une liste de chaînes
        List<String> books = new ArrayList<>();
        books.add("L'attrape-cœurs");
        books.add("De grandes espérances");
        books.add("La Divine Comédie");

        // 2. Enregistrer la liste dans un fichier
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("books.ser"));
        out.writeObject(books);
        out.close();

        // 3. Relire la liste depuis le fichier
        ObjectInputStream in = new ObjectInputStream(new FileInputStream("books.ser"));
        List<String> loadedBooks = (List<String>) in.readObject();
        in.close();

        // 4. Vérifier le résultat
        System.out.println("Liste des livres après désérialisation :");
        for (String book : loadedBooks) {
            System.out.println("- " + book);
        }
    }
}

Sortie :

Liste des livres après désérialisation :
- L'attrape-cœurs
- De grandes espérances
- La Divine Comédie

Exemple 2 : sérialisation 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("Ensemble après désérialisation : " + loadedNumbers);

Exemple 3 : sérialisation 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("Map après désérialisation : " + loadedScores);

Points importants

L’ordre est-il conservé ?

  • Pour List (par exemple, ArrayList), l’ordre des éléments est toujours conservé.
  • Pour Set (HashSet), l’ordre n’est pas garanti (avant comme après la sérialisation).
  • Pour Map (HashMap), l’ordre des paires clé-valeur n’est pas garanti (si vous avez besoin d’un ordre, utilisez LinkedHashMap).

Les collections vides se sérialisent et se désérialisent sans problème. Après désérialisation, vous obtiendrez une liste/un ensemble/une map vide.

Collections imbriquées (par exemple, List<List<String>>) se sérialisent correctement si tous les éléments imbriqués sont sérialisables.

2. Exigences relatives aux éléments d’une collection

C’est souvent ici que se cache le premier piège sérieux !

Tous les éléments de la collection doivent eux aussi être sérialisables.

Si au moins un élément de la collection n’implémente pas l’interface Serializable, la sérialisation de la collection échouera avec l’erreur NotSerializableException. Et si la collection est volumineuse et que l’erreur se trouve quelque part à l’intérieur, retrouver le coupable devient une véritable chasse au trésor.

Exemple : sérialisation d’une collection avec un objet non sérialisable

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)); // <- Oups !

        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("badlist.ser"));
        try {
            out.writeObject(list); // Une exception sera levée ici !
        } catch (NotSerializableException e) {
            System.out.println("Erreur de sérialisation : " + e);
        }
        out.close();
    }
}

Résultat :

Erreur de sérialisation : java.io.NotSerializableException: NotSerializableClass

Que faire ?

La solution est simple : tous les éléments de la collection doivent être soit des types standard tels que String ou Integer, soit vos propres classes qui implémentent l’interface Serializable. Si une classe n’est pas sérialisable, il suffit de lui ajouter implements Serializable, et le problème est résolu.

3. Particularités de la sérialisation selon les collections

L’ordre des éléments est-il conservé ?

  • List : Oui, l’ordre des éléments est conservé.
  • Set : Cela dépend de l’implémentation. Dans HashSet, l’ordre n’est pas garanti, alors que dans LinkedHashSet — il est conservé.
  • Map : Dans HashMap, l’ordre n’est pas garanti ; dans LinkedHashMap, l’ordre d’insertion est conservé.

Démonstration :

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); // toujours [A, B, C]
System.out.println("Set: " + loadedSet);   // peut être [A, C, B], etc.

Sérialisation des collections vides

Les collections vides se sérialisent sans problème. Après désérialisation, vous obtiendrez un objet vide du type souhaité.

Sérialisation des collections imbriquées

On peut sérialiser des collections qui en contiennent d’autres :

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

// Sérialisation
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("table.ser"));
out.writeObject(table);
out.close();

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

System.out.println(loadedTable);

4. Exemple pratique : sérialiser une collection d’objets de votre propre classe

Écrivons ensemble une petite application pour une « bibliothèque virtuelle », où nous sérialiserons une liste de livres. La classe Book doit être sérialisable !

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

class Book implements Serializable {
    private static final long serialVersionUID = 1L; // pour la compatibilité des versions de la 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("L'attrape-cœurs", "J. D. Salinger", 1951));
        books.add(new Book("De grandes espérances", "Charles Dickens", 1861));
        books.add(new Book("La Divine Comédie", "Dante Alighieri", 1320));

        // Enregistrer la liste dans un fichier
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("mylibrary.ser"));
        out.writeObject(books);
        out.close();

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

        System.out.println("Livres depuis le fichier :");
        for (Book b : loadedBooks) {
            System.out.println("- " + b);
        }
    }
}

5. Erreurs courantes lors de la sérialisation des collections

Erreur n° 1 : NotSerializableException sur un élément de la collection. Si au moins un élément de la collection n’est pas sérialisable, la sérialisation « échouera » avec l’erreur NotSerializableException. Par exemple, si vous avez ajouté par inadvertance à la collection un objet qui n’implémente pas Serializable, ou si vous avez oublié d’ajouter cette interface à votre classe.

Erreur n° 2 : Modification de la classe entre la sérialisation et la désérialisation. Si vous avez sérialisé une collection d’objets, puis modifié la structure de la classe (par exemple en ajoutant ou en supprimant des champs), lors de la désérialisation, une exception InvalidClassException peut survenir. Pour éviter cela, utilisez le champ serialVersionUID dans la classe.

Erreur n° 3 : Sérialisation d’une collection avec des champs transient ou static. Les champs marqués transient ou static ne sont pas sérialisés. Si vos objets dépendent de tels champs, après désérialisation, ils auront des valeurs par défaut (par exemple, null ou 0).

Erreur n° 4 : Sérialisation de collections avec des objets imbriqués non sérialisables. S’il y a des collections ou des objets imbriqués qui n’implémentent pas Serializable, l’erreur apparaîtra au niveau le plus profond — il n’est pas toujours évident de savoir où chercher le problème. Vérifiez tous les niveaux d’imbrication !

Erreur n° 5 : Performances avec de grandes collections. Si la collection est très volumineuse, la sérialisation peut prendre beaucoup de temps et d’espace disque. Dans ce cas, il convient d’envisager une sérialisation en flux ou une division de la collection en parties.

1
Étude/Quiz
Sérialisation, niveau 42, leçon 4
Indisponible
Sérialisation
Introduction à la sérialisation des objets
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION