1. Serialisierung von Collections
Gute Nachricht: Fast alle Standard-Collections in Java (z. B. ArrayList, HashSet, HashMap und ihre Freunde) implementieren bereits Serializable. Das bedeutet, dass Sie sie out of the box serialisieren können, ohne komplizierte Verrenkungen.
Beispiel:
import java.io.Serializable;
import java.util.ArrayList;
public class MyList extends ArrayList<String> implements Serializable {
// Man kann sogar gar nichts schreiben — ArrayList ist bereits Serializable!
}
In der Praxis serialisieren Sie üblicherweise Standard-Collections, und alles funktioniert ohne zusätzlichen Aufwand.
Wie serialisiert man eine Collection?
Für die Serialisierung einer Collection wird derselbe Ansatz verwendet wie für jedes andere Objekt:
- Collection erstellen.
- Sie über ObjectOutputStream in eine Datei schreiben.
- Über ObjectInputStream wieder einlesen.
Beispiel 1: Serialisierung ArrayList<String>
import java.io.*;
import java.util.*;
public class SerializeListDemo {
public static void main(String[] args) throws Exception {
// 1. Wir erstellen eine String-Liste
List<String> books = new ArrayList<>();
books.add("Der Fänger im Roggen");
books.add("Große Erwartungen");
books.add("Die Göttliche Komödie");
// 2. Wir speichern die Liste in eine Datei
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("books.ser"));
out.writeObject(books);
out.close();
// 3. Wir lesen die Liste wieder aus der Datei
ObjectInputStream in = new ObjectInputStream(new FileInputStream("books.ser"));
List<String> loadedBooks = (List<String>) in.readObject();
in.close();
// 4. Wir prüfen das Ergebnis
System.out.println("Liste der Bücher nach der Deserialisierung:");
for (String book : loadedBooks) {
System.out.println("- " + book);
}
}
}
Ausgabe:
Liste der Bücher nach der Deserialisierung:
- Der Fänger im Roggen
- Große Erwartungen
- Die Göttliche Komödie
Beispiel 2: Serialisierung 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("Menge nach der Deserialisierung: " + loadedNumbers);
Beispiel 3: Serialisierung 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 nach der Deserialisierung: " + loadedScores);
Wichtige Punkte
Bleibt die Reihenfolge erhalten?
- Für List (z. B. ArrayList) bleibt die Reihenfolge der Elemente immer erhalten.
- Für Set (HashSet) wird die Reihenfolge nicht garantiert (sowohl vor als auch nach der Serialisierung).
- Für Map (HashMap) ist die Reihenfolge der Schlüssel-Wert-Paare nicht garantiert (wenn Sie eine Reihenfolge benötigen — verwenden Sie LinkedHashMap).
Leere Collections werden ohne Probleme serialisiert und deserialisiert. Nach der Deserialisierung erhalten Sie eine leere Liste/Menge/Map.
Verschachtelte Collections (z. B. List<List<String>>) werden korrekt serialisiert, sofern alle verschachtelten Elemente serialisierbar sind.
2. Anforderungen an die Elemente einer Collection
Hier lauert oft die erste ernsthafte Falle!
Alle Elemente der Collection müssen ebenfalls serialisierbar sein.
Wenn nur ein einziges Element der Collection das Interface Serializable nicht implementiert, endet die Serialisierung der Collection mit dem Fehler NotSerializableException. Und wenn die Collection groß ist und der Fehler irgendwo im Inneren steckt, wird die Suche nach dem Übeltäter schnell zur mühsamen Fehlersuche.
Beispiel: Serialisierung einer Collection mit einem nicht serialisierbaren Objekt
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)); // <- Hoppla!
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("badlist.ser"));
try {
out.writeObject(list); // Hier wird eine Exception ausgelöst!
} catch (NotSerializableException e) {
System.out.println("Serialisierungsfehler: " + e);
}
out.close();
}
}
Ergebnis:
Serialisierungsfehler: java.io.NotSerializableException: NotSerializableClass
Was tun?
Die Lösung ist einfach: Alle Elemente der Collection sollten entweder Standardtypen wie String oder Integer sein oder Ihre eigenen Klassen, die das Interface Serializable implementieren. Wenn eine Klasse nicht serialisierbar ist, genügt es, ihr implements Serializable hinzuzufügen, und das Problem ist behoben.
3. Besonderheiten der Serialisierung verschiedener Collections
Bleibt die Reihenfolge der Elemente erhalten?
- List: Ja, die Reihenfolge der Elemente bleibt erhalten.
- Set: Hängt von der Implementierung ab. In HashSet ist die Reihenfolge nicht garantiert, in LinkedHashSet hingegen bleibt sie erhalten.
- Map: In HashMap ist die Reihenfolge nicht garantiert, in LinkedHashMap bleibt die Einfüge-Reihenfolge erhalten.
Demonstration:
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); // immer [A, B, C]
System.out.println("Set: " + loadedSet); // kann [A, C, B] usw. sein
Serialisierung leerer Collections
Leere Collections werden ohne Probleme serialisiert. Nach der Deserialisierung erhalten Sie ein leeres Objekt des gewünschten Typs.
Serialisierung verschachtelter Collections
Sie können Collections serialisieren, die andere Collections enthalten:
List<List<String>> table = new ArrayList<>();
table.add(Arrays.asList("row1-col1", "row1-col2"));
table.add(Arrays.asList("row2-col1", "row2-col2"));
// Serialisierung
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("table.ser"));
out.writeObject(table);
out.close();
// Deserialisierung
ObjectInputStream in = new ObjectInputStream(new FileInputStream("table.ser"));
List<List<String>> loadedTable = (List<List<String>>) in.readObject();
in.close();
System.out.println(loadedTable);
4. Praxisbeispiel: Serialisierung einer Collection von Objekten einer eigenen Klasse
Schreiben wir gemeinsam eine kleine Anwendung für eine „virtuelle Bibliothek“, in der wir eine Bücherliste serialisieren. Die Klasse Book muss serialisierbar sein!
import java.io.*;
import java.util.*;
class Book implements Serializable {
private static final long serialVersionUID = 1L; // für die Kompatibilität von Klassenversionen
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("Der Fänger im Roggen", "J. D. Salinger", 1951));
books.add(new Book("Große Erwartungen", "Charles Dickens", 1861));
books.add(new Book("Die Göttliche Komödie", "Dante Alighieri", 1320));
// Wir speichern die Liste in eine Datei
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("mylibrary.ser"));
out.writeObject(books);
out.close();
// Wir lesen die Liste wieder ein
ObjectInputStream in = new ObjectInputStream(new FileInputStream("mylibrary.ser"));
List<Book> loadedBooks = (List<Book>) in.readObject();
in.close();
System.out.println("Bücher aus der Datei:");
for (Book b : loadedBooks) {
System.out.println("- " + b);
}
}
}
5. Typische Fehler bei der Serialisierung von Collections
Fehler Nr. 1: NotSerializableException bei einem Collection-Element. Wenn auch nur ein Element der Collection nicht serialisierbar ist, „scheitert“ die Serialisierung mit NotSerializableException. Zum Beispiel, wenn Sie versehentlich ein Objekt zur Collection hinzugefügt haben, das Serializable nicht implementiert, oder vergessen haben, dieses Interface Ihrer Klasse hinzuzufügen.
Fehler Nr. 2: Änderung der Klasse zwischen Serialisierung und Deserialisierung. Wenn Sie eine Collection von Objekten serialisiert haben und anschließend die Klassenstruktur ändern (z. B. Felder hinzufügen oder löschen), kann bei der Deserialisierung eine InvalidClassException auftreten. Verwenden Sie zur Vermeidung das Feld serialVersionUID in der Klasse.
Fehler Nr. 3: Serialisierung von Collections mit transient- oder static-Feldern. Felder, die als transient oder static markiert sind, werden nicht serialisiert. Wenn Ihre Objekte von solchen Feldern abhängen, haben sie nach der Deserialisierung Standardwerte (z. B. null oder 0).
Fehler Nr. 4: Serialisierung von Collections mit verschachtelten nicht serialisierbaren Objekten. Wenn es in der Collection verschachtelte Collections oder Objekte gibt, die Serializable nicht implementieren, tritt der Fehler auf der tiefsten Ebene auf — es ist nicht immer sofort klar, wo das Problem liegt. Prüfen Sie alle Verschachtelungsebenen!
Fehler Nr. 5: Leistung bei großen Collections. Wenn die Collection sehr groß ist, kann die Serialisierung viel Zeit und Speicherplatz beanspruchen. In solchen Fällen sollten Sie über Streaming-Serialisierung oder eine Aufteilung der Collection in Teile nachdenken.
GO TO FULL VERSION