CodeGym /Cursos /JAVA 25 SELF /Serialización de colecciones: List, Map, Set

Serialización de colecciones: List, Map, Set

JAVA 25 SELF
Nivel 42, Lección 4
Disponible

1. Serialización de colecciones

Buenas noticias: casi todas las colecciones estándar de Java (por ejemplo, ArrayList, HashSet, HashMap y sus compañeras) ya implementan Serializable. Esto significa que puedes serializarlas directamente, sin complicaciones.

Ejemplo:

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

public class MyList extends ArrayList<String> implements Serializable {
    // Ni siquiera hace falta escribir nada — ¡ArrayList ya es Serializable!
}

En la práctica, normalmente serializas colecciones estándar y todo funciona sin mayores esfuerzos.

¿Cómo serializar una colección?

Para serializar una colección se utiliza el mismo enfoque que para cualquier otro objeto:

  • Creamos la colección.
  • La escribimos a un archivo mediante ObjectOutputStream.
  • La leemos de vuelta mediante ObjectInputStream.

Ejemplo 1: Serialización ArrayList<String>

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

public class SerializeListDemo {
    public static void main(String[] args) throws Exception {
        // 1. Creamos una lista de cadenas
        List<String> books = new ArrayList<>();
        books.add("El guardián entre el centeno");
        books.add("Grandes esperanzas");
        books.add("La Divina Comedia");

        // 2. Guardamos la lista en un archivo
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("books.ser"));
        out.writeObject(books);
        out.close();

        // 3. Leemos la lista de vuelta del archivo
        ObjectInputStream in = new ObjectInputStream(new FileInputStream("books.ser"));
        List<String> loadedBooks = (List<String>) in.readObject();
        in.close();

        // 4. Verificamos el resultado
        System.out.println("Lista de libros después de la deserialización:");
        for (String book : loadedBooks) {
            System.out.println("- " + book);
        }
    }
}

Salida:

Lista de libros después de la deserialización:
- El guardián entre el centeno
- Grandes esperanzas
- La Divina Comedia

Ejemplo 2: Serialización de 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("Conjunto después de la deserialización: " + loadedNumbers);

Ejemplo 3: Serialización de 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("Mapa después de la deserialización: " + loadedScores);

Puntos importantes

¿Se conserva el orden?

  • Para List (por ejemplo, ArrayList) el orden de los elementos siempre se conserva.
  • Para Set (HashSet) el orden no está garantizado (tanto antes como después de la serialización).
  • Para Map (HashMap) el orden de los pares clave-valor no está garantizado (si necesitas orden — usa LinkedHashMap).

Las colecciones vacías se serializan y deserializan sin problemas. Tras la deserialización obtendrás una lista/conjunto/mapa vacío.

Las colecciones anidadas (por ejemplo, List<List<String>>) se serializan correctamente si todos los elementos anidados son serializables.

2. Requisitos para los elementos de la colección

¡Aquí suele acechar la primera trampa importante!

Todos los elementos de la colección también deben ser serializables.

Si al menos un elemento de la colección no implementa la interfaz Serializable, la serialización de la colección terminará con un error NotSerializableException. Y si la colección es grande y el error está en alguna parte interna, encontrar al culpable se convierte en toda una búsqueda.

Ejemplo: serialización de una colección con un objeto no serializable

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

        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("badlist.ser"));
        try {
            out.writeObject(list); // ¡Aquí se lanzará una excepción!
        } catch (NotSerializableException e) {
            System.out.println("Error de serialización: " + e);
        }
        out.close();
    }
}

Resultado:

Error de serialización: java.io.NotSerializableException: NotSerializableClass

¿Qué hacer?

La solución es sencilla: todos los elementos de la colección deben ser o bien tipos estándar, como String o Integer, o bien tus propias clases que implementen la interfaz Serializable. Si alguna clase no es serializable, basta con añadirle implements Serializable, y el problema quedará resuelto.

3. Particularidades de la serialización de distintas colecciones

¿Se conserva el orden de los elementos?

  • List: Sí, el orden de los elementos se conserva.
  • Set: Depende de la implementación. En HashSet el orden no está garantizado, mientras que en LinkedHashSet sí se conserva.
  • Map: En HashMap el orden no está garantizado, en LinkedHashMap se conserva el orden de inserción.

Demostración:

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

Serialización de colecciones vacías

Las colecciones vacías se serializan sin problemas. Tras la deserialización obtendrás un objeto vacío del tipo necesario.

Serialización de colecciones anidadas

Se pueden serializar colecciones que contienen otras colecciones:

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

// Serialización
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("table.ser"));
out.writeObject(table);
out.close();

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

System.out.println(loadedTable);

4. Ejemplo práctico: serialización de una colección de objetos de una clase propia

Escribamos juntos una pequeña aplicación para una «biblioteca virtual», donde serializaremos una lista de libros. ¡La clase Book debe ser serializable!

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

class Book implements Serializable {
    private static final long serialVersionUID = 1L; // para la compatibilidad entre versiones de la clase
    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("El guardián entre el centeno", "J. D. Salinger", 1951));
        books.add(new Book("Grandes esperanzas", "Charles Dickens", 1861));
        books.add(new Book("La Divina Comedia", "Dante Alighieri", 1320));

        // Guardamos la lista en un archivo
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("mylibrary.ser"));
        out.writeObject(books);
        out.close();

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

        System.out.println("Libros del archivo:");
        for (Book b : loadedBooks) {
            System.out.println("- " + b);
        }
    }
}

5. Errores típicos al serializar colecciones

Error n.º 1: NotSerializableException en un elemento de la colección. Si al menos un elemento de la colección no es serializable, la serialización «fallará» con el error NotSerializableException. Por ejemplo, si añadiste por accidente a la colección un objeto que no implementa Serializable, o si olvidaste añadir esa interfaz a tu clase.

Error n.º 2: Cambio de la clase entre la serialización y la deserialización. Si serializaste una colección de objetos y luego cambiaste la estructura de la clase (por ejemplo, añadiste o eliminaste campos), durante la deserialización puede producirse una excepción InvalidClassException. Para evitarlo, utiliza el campo serialVersionUID en la clase.

Error n.º 3: Serialización de una colección con campos transient o static. Los campos marcados como transient o static no se serializan. Si tus objetos dependen de esos campos, tras la deserialización tendrán valores por defecto (por ejemplo, null o 0).

Error n.º 4: Serialización de colecciones con objetos anidados no serializables. Si en la colección hay colecciones u objetos anidados que no implementan Serializable, el error aparecerá en el nivel más profundo — no siempre queda claro dónde buscar el problema. ¡Comprueba todos los niveles de anidación!

Error n.º 5: Rendimiento con colecciones grandes. Si la colección es muy grande, la serialización puede llevar mucho tiempo y ocupar mucho espacio en disco. En esos casos conviene pensar en serialización por streaming o en dividir la colección en partes.

1
Tarea
JAVA 25 SELF, nivel 42, lección 4
Bloqueada
Serialización de una lista de cadenas
Serialización de una lista de cadenas
1
Tarea
JAVA 25 SELF, nivel 42, lección 4
Bloqueada
Serialización del mapa de calificaciones
Serialización del mapa de calificaciones
1
Cuestionario/control
Serialización, nivel 42, lección 4
No disponible
Serialización
Introducción a la serialización de objetos
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION