W3docs

Überblick über das Java Collections Framework

Ein Überblick über das Java Collections Framework — Interfaces, Implementierungen und Algorithmen in java.util.

Fast jedes Programm muss irgendwann eine Gruppe von Dingen verwalten — ausstehende Bestellungen, Wörter in einem Dokument, aktuell angemeldete Benutzer oder die Warteschlange von Aufgaben, die ein Worker-Thread abarbeiten soll. Javas Antwort auf die Frage „Wo soll ich diese Gruppe ablegen?" ist das Collections Framework: eine koordinierte Menge von Interfaces in java.util, mehr als ein Dutzend Implementierungen dahinter und eine einzige Hilfsklasse mit Algorithmen (Collections), die gegen die Interfaces und nicht gegen eine bestimmte Implementierung arbeitet. Dieses Kapitel ist die Karte — was im Framework steckt, warum es so aufgebaut ist und welche Familie in welcher Situation die richtige Wahl ist. Jedes Kapitel in diesem Teil widmet sich einer der Boxen auf dieser Karte.

Warum ein Framework und nicht einfach Klassen

Vor Java 1.2 gab es zwar Klassen für Gruppen (Vector, Hashtable, Stack), aber kein gemeinsames Interface — man konnte keine Methode schreiben, die „irgendeine Liste" entgegennimmt und alle drei akzeptiert. Das Collections Framework hat das behoben, indem es was eine Gruppe ist (das Interface) von wie sie gespeichert wird (die Implementierung) trennt. Der Nutzen zeigt sich täglich:

// You program against the interface, not the class.
List<String> names = new ArrayList<>();
// Later, swap in a different implementation without touching the rest of the code:
List<String> names = new LinkedList<>();

Jede Methode, die auf names aufgerufen wird, ist auf List definiert. Die Wahl zwischen ArrayList und LinkedList ist eine Leistungsentscheidung, keine API-Entscheidung. Man kann auch Methoden wie void print(List<String> xs) einmal schreiben und beide Implementierungen übergeben.

Die vier Wurzel-Interfaces

Das Framework ist um vier Wurzel-Interfaces herum organisiert. Man wählt dasjenige, dessen Vertrag zu den eigenen Daten passt:

  • Collection<E> — die Wurzel. Eine Gruppe von E-Elementen. Keine Aussage über Reihenfolge, Duplikate oder Indizierung.
  • List<E> — eine geordnete Collection, zugänglich per Index. Duplikate erlaubt. Denk daran als „Array, das wächst" oder „verkettete Sequenz." ArrayList, LinkedList, Vector.
  • Set<E> — eine Collection, die Duplikate verbietet. Mathematische Menge. Kann geordnet sein oder nicht. HashSet, LinkedHashSet, TreeSet.
  • Map<K, V> — Schlüssel→Wert-Nachschlagen. Keine Collection (seine Elemente sind Einträge, keine Einzelwerte), gehört aber zum Framework. HashMap, LinkedHashMap, TreeMap.

Zwei weitere stehen neben List und Set als Spezialisierungen von Collection:

  • Queue<E> — eine „nächster in der Reihe"-Collection. Standardmäßig FIFO. LinkedList, ArrayDeque, PriorityQueue.
  • Deque<E> — eine doppelseitige Queue. Hinzufügen und Entfernen an beiden Enden. ArrayDeque, LinkedList.

Jede Collection-Klasse in der Standardbibliothek implementiert mindestens eines dieser Interfaces.

Familie nach Verhalten wählen, dann Klasse nach Kosten

Die Entscheidung erfolgt in zwei Schritten:

  1. Was brauchen die Daten? Geordnet mit Duplikaten → List. Keine Duplikate → Set. Nachschlagen per Schlüssel → Map. Produzent/Konsument → Queue oder Deque.
  2. Welche Zugriffsmuster gibt es innerhalb der Familie? Wahlfreier Zugriff per Index → ArrayList. Häufiges Hinzufügen/Entfernen am Anfang → LinkedList oder ArrayDeque. Sortierte Iteration → TreeSet / TreeMap. Einfach „schnelle Menge gesucht" → HashSet / HashMap.

Eine grobe Übersicht für die häufigsten Fälle:

BedarfVerwendeHinweise
Veränderliche Liste, schneller wahlfreier ZugriffArrayListDie Standard-List.
Liste mit sehr häufigem Einfügen/Entfernen an den EndenArrayDeque (als listenähnliche Queue)Schlägt LinkedList in der Praxis.
Menge, schnelles contains/add/removeHashSetKeine Reihenfolgegarantie.
Menge mit vorhersehbarer IterationLinkedHashSetIteration in Einfügereihenfolge.
Sortierte MengeTreeSetO(log n) Operationen.
Map, schnelles NachschlagenHashMapDie Standard-Map.
Map mit vorhersehbarer IterationLinkedHashMapNützlich für Caches (LRU).
Sortierte MapTreeMapSchlüssel in sortierter Reihenfolge.
FIFO-QueueArrayDequeSchneller als LinkedList.
Immer-das-Kleinste-EntnehmenPriorityQueueHeap-basiert.

Vector, Stack und Hashtable sind die Klassen aus der Zeit vor 1.2 — noch im JDK für Abwärtskompatibilität, aber keine gute Wahl für neuen Code. Ihre modernen Ersatzklassen werden in eigenen Kapiteln behandelt.

Generics machen Collections typsicher

Jedes Collection-Interface und jede Klasse ist generisch. Man parametrisiert es mit dem Elementtyp bei der Deklaration, und der Compiler erzwingt dies ab dann:

List<String> names = new ArrayList<>();
names.add("Ada");
names.add(42);          // ❌ compile error — Integer is not a String
String first = names.get(0);   // no cast needed

Das Diamond-Symbol <> auf der rechten Seite weist den Compiler an, den Typ von der linken Seite abzuleiten — das spart Tipparbeit ohne den Sicherheitsvorteil zu verlieren. Der vorherige Teil des Buchs (Generics) ist das Regelwerk hinter all dem; der Rest dieses Teils setzt voraus, dass dieser gelesen wurde.

Algorithmen leben auf der Collections-Klasse

Operationen, die nicht an eine bestimmte Implementierung gebunden sind — sortieren, mischen, umkehren, Binärsuche, min, max, Häufigkeit, unveränderliche Wrapper — befinden sich auf der statischen Hilfsklasse java.util.Collections. Achtung auf das s am Ende: Collection (das Interface) ist ein Element; Collections (die Klasse) ist das Werkzeugkasten:

List<Integer> xs = new ArrayList<>(List.of(3, 1, 4, 1, 5, 9, 2, 6));
Collections.sort(xs);                    // mutates xs
int idx = Collections.binarySearch(xs, 5);
List<Integer> ro = Collections.unmodifiableList(xs);

Gegen Ende dieses Teils widmen wir drei Kapitel Collections — Suchen, Sortieren und unveränderliche Wrapper — da die Hilfsklasse der Ort ist, an dem viel praktische Arbeit stattfindet.

Eine erste vollständige Tour

Das folgende Programm wählt einen Vertreter aus jeder Familie und zeigt die Operationen, die immer wieder verwendet werden. Keine Sorge, wenn noch nicht jede Zeile verständlich ist — jede Klasse hier bekommt ihr eigenes Kapitel. Ziel ist es, die Form des Frameworks zu sehen: gleiche Methodennamen, gleiche Muster, gleiche Iteration.

java— editable, runs on the server

In der Ausgabe fallen drei Dinge auf:

  1. Das Set hat das Duplikat "Effective Java" stillschweigend entfernt. Das ist der Vertrag — kein zusätzlicher Code auf der eigenen Seite nötig.
  2. Die Queue gab Elemente in der Reihenfolge zurück, in der sie hinzugefügt wurden. offer fügt ein, peek schaut auf den Kopf ohne zu entfernen, poll entfernt und gibt zurück.
  3. Die for-each-Schleife funktioniert auf jeder Collection. Maps iterieren über entrySet(), keySet() oder values(), je nachdem was benötigt wird.

Das ist das Framework in der Kurzfassung.

Warnung

HashSet und HashMap machen keine Aussage über die Iterationsreihenfolge — die oben in der Ausgabe gezeigte Reihenfolge ist ein Implementierungsdetail und kann zwischen JVM-Versionen oder Läufen variieren. Wenn eine stabile Reihenfolge benötigt wird, greife auf LinkedHashSet/LinkedHashMap (Einfügereihenfolge) oder TreeSet/TreeMap (sortierte Reihenfolge) zurück. Schreibe niemals Code, der von der Iterationsreihenfolge eines einfachen HashSet oder HashMap abhängt.

Was kommt als Nächstes

Die Karte ist nun bekannt. Der Rest von Teil 11 erkundet jede Region. Der natürliche Ausgangspunkt ist die Wurzel, von der jede Collection erbt — das Collection-Interface selbst, wo Methoden wie add, remove, contains, size und iterator() ein für alle Mal definiert sind.

Übungen

Übung
Du musst eine Gruppe von Wörtern speichern und schnell beantworten, ob ein bestimmtes Wort in der Gruppe vorhanden ist. Duplikate sind nicht relevant — `cat` ist entweder da oder nicht. Welche Familie des Collections Framework ist die natürliche Wahl?
Du musst eine Gruppe von Wörtern speichern und schnell beantworten, ob ein bestimmtes Wort in der Gruppe vorhanden ist. Duplikate sind nicht relevant — `cat` ist entweder da oder nicht. Welche Familie des Collections Framework ist die natürliche Wahl?
Was this page helpful?