CodeGym /Kurse /JAVA 25 SELF /Mutable vs Immutable Kollektionen: Unterschiede und Einsa...

Mutable vs Immutable Kollektionen: Unterschiede und Einsatz

JAVA 25 SELF
Level 34, Lektion 3
Verfügbar

1. Einführung

Ganz einfach gesagt: Eine mutable-Kollektion ist eine, die man nach der Erstellung ändern kann: Elemente hinzufügen, entfernen und verändern. Eine immutable (unveränderliche) Kollektion ist eine Kollektion, die man nach der Erstellung nicht mehr ändern kann. Wie Beton nach dem Aushärten: Man kann ihn anschauen und anfassen, aber neue Figürchen formen geht nicht mehr.

Eine mutable-Kollektion ist wie ein Notizblock mit Bleistift: Sie schreiben, radieren, fügen neue Notizen hinzu. Eine immutable-Kollektion ist wie eine laminierten Seite: Jetzt kann niemand mehr etwas hinzufügen oder löschen.

Beispiele für veränderliche (mutable) Kollektionen

In Java sind fast alle Standardkollektionen standardmäßig veränderlich. Dazu gehören Klassen wie:

  • ArrayList
  • LinkedList
  • HashSet
  • TreeSet
  • HashMap
  • LinkedHashMap
  • und viele andere

Beispiel: ArrayList

import java.util.*;

List<String> names = new ArrayList<>();
names.add("Alice");
names.add("Bob");
names.set(1, "Charlie"); // Bob durch Charlie ersetzt
names.remove("Alice");   // Alice entfernt
System.out.println(names); // [Charlie]

Hier können wir mit der Kollektion alles Mögliche tun: Elemente hinzufügen, entfernen, vertauschen. Das ist praktisch, wenn die Kollektion dynamisch aufgebaut wird, zum Beispiel beim Einlesen von Daten aus einer Datei oder Benutzereingaben.

2. Beispiele für unveränderliche (immutable) Kollektionen

Mit diesen Kandidaten, die in Java 9 eingeführt wurden, sind Sie vermutlich schon in Berührung gekommen, aber man muss sich an sie noch gewöhnen:

  • List.of(...)
  • Set.of(...)
  • Map.of(...)
  • List.copyOf(collection)
  • Set.copyOf(collection)
  • Map.copyOf(map)

Beispiel: List.of

List<String> planets = List.of("Mercury", "Venus", "Earth", "Mars");
System.out.println(planets); // [Mercury, Venus, Earth, Mars]
planets.add("Jupiter"); // Wirft UnsupportedOperationException!

Ein Änderungsversuch an der Kollektion führt zu einer Laufzeitausnahme.

Beispiel: Collections.unmodifiableList

List<String> modifiable = new ArrayList<>(List.of("a", "b"));
List<String> unmodifiable = Collections.unmodifiableList(modifiable);
unmodifiable.add("c"); // UnsupportedOperationException!

Aber hier gibt es einen Haken: Wenn Sie die Ausgangskollektion ändern, ändert sich auch der Wrapper!

modifiable.add("c");
System.out.println(unmodifiable); // [a, b, c] — Element ist hinzugekommen!

3. Wesentliche Unterschiede zwischen mutable und immutable Kollektionen

Eigenschaft Mutable (veränderlich) Immutable (unveränderlich)
Kann man ein Element hinzufügen? Ja Nein
Kann man ein Element entfernen? Ja Nein
Kann man ein Element ändern? Ja (z. B. set) Nein
Thread-Sicherheit Nein (standardmäßig) Ja (kein Zustand — nichts zu ändern)
Darf null hinzugefügt werden? Ja (in der Regel) Nein (in den Fabrikmethoden ab Java 9+)
Implementierung ArrayList, HashSet usw. List.of, Set.of, Map.of, copyOf

4. Warum braucht man überhaupt unveränderliche Kollektionen?

Es stellt sich sofort die Frage: Wenn veränderliche Kollektionen so flexibel sind, warum brauchen wir dann unveränderliche? Es gibt viele Gründe, sie hängen alle mit Sicherheit, Lesbarkeit und Vorhersagbarkeit des Codes zusammen.

Sicherheit und Schutz vor Fehlern

Wenn Sie eine Kollektion nach außen geben (zum Beispiel aus einer Methode oder Klasse), möchten Sie sicher sein, dass niemand versehentlich ihren Inhalt ändert. Besonders wichtig ist das, wenn die Kollektion „wichtige“ Daten enthält, die nach der Initialisierung nicht verändert werden dürfen.

Beispiel:

public class Team {
    private final List<String> players;

    public Team(List<String> players) {
        // Wir erstellen eine unveränderliche Kopie, damit niemand die Aufstellung manipulieren kann
        this.players = List.copyOf(players);
    }

    public List<String> getPlayers() {
        return players;
    }
}

Nun kann jeder Code, der die Spielerliste erhält, dort keinen „Freund“ hinzufügen.

Thread-Sicherheit

Veränderliche Kollektionen sind bei gleichzeitigem Zugriff aus mehreren Threads nicht sicher. Unveränderliche Kollektionen hingegen kann man gefahrlos zwischen Threads übergeben — niemand kann sie verderben.

Vereinfachte Fehlersuche

Wenn sich eine Kollektion nicht ändert, wissen Sie immer, was sie enthält. Sie müssen keine Angst haben, dass sie jemand „hinter Ihrem Rücken“ an anderer Stelle im Code verändert hat.

Einsatz als Schlüssel oder Werte in anderen Kollektionen

Unveränderliche Objekte sind ideale Kandidaten als Schlüssel in einer Map oder Elemente in einem Set. Wenn sich ein Objekt nach dem Einfügen ändern kann, riskieren Sie, den Zugriff darauf zu verlieren (siehe hashCode und equals).

5. Wann sollte man veränderliche Kollektionen verwenden?

Veränderliche Kollektionen sind gut, wenn:

  • Die Kollektion schrittweise aufgebaut wird, in einer Schleife oder aus verschiedenen Quellen.
  • Häufige Änderungen nötig sind: Hinzufügen, Entfernen, Sortieren.
  • Die Kollektion für die interne Verwendung gedacht ist und niemand „von außen“ sie verderben kann.

Beispiel: Aufbau einer Liste

List<String> shoppingList = new ArrayList<>();
shoppingList.add("Milch");
shoppingList.add("Brot");
shoppingList.add("Äpfel");
// Nach dem Aufbau — man kann eine unveränderliche Version erstellen
List<String> finalList = List.copyOf(shoppingList);

6. Wann sollte man unveränderliche Kollektionen verwenden?

  • Zum Speichern konstanter Daten (z. B. die Liste der Wochentage).
  • Zur Übergabe von Kollektionen zwischen Schichten der Anwendung (z. B. vom DAO zum Service).
  • Für Rückgaben aus Methoden, um sie vor Änderungen zu schützen.
  • Für Mehrfaden-Szenarien, in denen Sicherheit wichtig ist.

Beispiel: Konstante Daten

public static final List<String> WEEKDAYS = List.of(
    "Monday", "Tuesday", "Wednesday", "Thursday", "Friday"
);

Beispiel: Übergabe nach außen

public List<String> getReadOnlyNames() {
    return List.copyOf(names); // niemand kann die Liste ändern
}

7. Besonderheiten und Fallstricke

Unveränderlichkeit ≠ Thread-Sicherheit

Eine unveränderliche Kollektion ist vor Änderungen geschützt, aber das bedeutet nicht, dass sie vor anderen Problemen in einer Mehrfadenumgebung geschützt ist (zum Beispiel, wenn die Elemente der Kollektion veränderliche Objekte sind).

List<List<String>> listOfLists = List.of(new ArrayList<>());
listOfLists.get(0).add("Oops!"); // Die innere Liste lässt sich ändern!

Wrapper vs. Kopien

Wie bereits erwähnt ist Collections.unmodifiableList ein Wrapper, und wenn die Ausgangskollektion geändert wird, ändert sich auch der Wrapper. List.copyOf hingegen erstellt eine echte, unabhängige Kopie.

List<String> base = new ArrayList<>(List.of("a", "b"));
List<String> wrap = Collections.unmodifiableList(base);
List<String> copy = List.copyOf(base);

base.add("c");
System.out.println(wrap); // [a, b, c] — hat sich geändert!
System.out.println(copy); // [a, b] — ist unverändert geblieben!

NullPointerException

Die Fabrikmethoden (List.of, Set.of, Map.of) lassen null nicht zu:

List<String> bad = List.of("a", null); // Wirft bereits bei der Erstellung eine NullPointerException!

8. Vergleich der Ansätze: Vor- und Nachteile

Veränderliche Kollektionen

Der Hauptvorteil veränderlicher Kollektionen ist ihre Flexibilität. Sie können Elemente im laufenden Betrieb hinzufügen und entfernen, die Kollektion mit der Zeit gemäß der Logik des Programms umbauen. Dieser Ansatz ist besonders bequem, wenn man schnell eine temporäre Struktur zusammensetzen oder etwas dynamisch ändern muss.

Aber für den Komfort zahlt man einen Preis. Eine veränderliche Kollektion birgt immer das Risiko unbeabsichtigter Eingriffe: Jemand im Code kann die Daten versehentlich ändern, was zu schwer auffindbaren Fehlern führt. In Mehrfaden-Programmen ist die Situation noch schlimmer — parallele Änderungen führen leicht zu Race Conditions und unerwarteten Ausfällen. Auch den Lebenszyklus solcher Daten zu kontrollieren ist komplizierter: Man muss ständig im Blick behalten, wer die Kollektion wann ändern kann.

Unveränderliche Kollektionen

Mit unveränderlichen Kollektionen arbeitet es sich entspannter. Sie wissen genau: Niemand wird sie „hinter Ihrem Rücken“ anpassen. Das macht den Code sicherer, erleichtert das Debugging und Testen, und die Kollektionen lassen sich ohne zusätzliche Sperren bequem zwischen Threads weitergeben.

Der Nachteil ist, dass man gelegentlich Leistung opfert. Wenn ein neues Element hinzugefügt werden soll, muss eine neue Kopie der Kollektion erstellt werden, was zusätzlichen Speicher- und Zeitaufwand bedeutet. Zudem ist es manchmal unpraktisch, große und komplexe Strukturen sofort in unveränderlicher Form zu erstellen. Üblicherweise baut man sie zunächst in einer temporären veränderlichen Kollektion auf und „friert“ sie ein, wenn alles fertig ist.

9. Typische Fehler

Fehler Nr. 1: Eine veränderliche Kollektion nach außen zurückgeben. Wenn Sie aus einer Methode eine gewöhnliche ArrayList zurückgeben, kann beliebiger externer Code Elemente hinzufügen oder entfernen. Das kann zu Bugs führen, die sehr schwer nachzuvollziehen sind.

Fehler Nr. 2: Wrapper statt Kopie verwenden. Wenn Sie Collections.unmodifiableList verwenden, die Ausgangskollektion aber an anderer Stelle geändert wird, ist die „Unveränderlichkeit“ nur eine Illusion.

Fehler Nr. 3: Veränderliche Objekte innerhalb von immutable-Kollektionen. Auch wenn die Kollektion selbst unveränderlich ist, können ihre Elemente veränderlich sein. Das kann zu unerwarteten Zustandsänderungen führen.

Fehler Nr. 4: Versuch, null zu einer über Fabrikmethoden erstellten Kollektion hinzuzufügen. Im Unterschied zu älteren Kollektionen lassen die neuen Fabrikmethoden null nicht zu — Sie erhalten eine NullPointerException.

Fehler Nr. 5: Auf eine konkrete Implementierung vertrauen. Kollektionen, die über List.of oder Set.of erstellt werden, garantieren keinen Implementierungstyp (das ist nicht zwangsläufig ArrayList oder HashSet). Verlassen Sie sich nicht darauf.

1
Aufgabe
JAVA 25 SELF, Level 34, Lektion 3
Gesperrt
Tierinventar: Live-Liste oder statische Momentaufnahme? 🐾
Tierinventar: Live-Liste oder statische Momentaufnahme? 🐾
1
Aufgabe
JAVA 25 SELF, Level 34, Lektion 3
Gesperrt
Playlists: die Sammlung ist unveränderlich, aber die Songs darin ändern sich 🎶
Playlists: die Sammlung ist unveränderlich, aber die Songs darin ändern sich 🎶
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION