Collections
Kurz: Javas Standard-Framework (java.util) für Datenstrukturen mit variabler Größe — die zentralen Interfaces sind List, Set und Map.
Genauer: Anders als Arrays haben Collections keine feste Größe und bieten fertige Methoden für Sortieren, Suchen und Filtern. Seit Java 5 sind Collections generisch (siehe Generics) — List<String> erzwingt zur Compile-Zeit, dass nur String-Objekte hineinkommen, statt Typfehler erst zur Laufzeit zu entdecken.
Im Detail
Das Collections-Framework ist als Hierarchie von Interfaces aufgebaut, die jeweils mehrere konkrete Implementierungen mit unterschiedlichen Performance-Eigenschaften haben:
List<String> geordnet = new ArrayList<>(); // erlaubt Duplikate, Reihenfolge bleibt erhalten
Set<String> eindeutig = new HashSet<>(); // keine Duplikate, KEINE garantierte Reihenfolge
Map<String, Integer> zuordnung = new HashMap<>(); // Schlüssel-Wert-Paare
geordnet.add("Ben"); geordnet.add("Ben"); // beide landen drin
eindeutig.add("Ben"); eindeutig.add("Ben"); // nur einmal enthalten
zuordnung.put("Ben", 25);
zuordnung.get("Ben"); // 25Die utility-Klasse Collections (Singular vs. Plural ist eine häufige Verwechslung: java.util.Collection ist das Basis-Interface, java.util.Collections die Klasse mit statischen Hilfsmethoden wie sort(), max(), unmodifiableList()) bietet fertige Algorithmen, die auf jeder Collection funktionieren, ohne dass man sie selbst implementieren muss. Collections.unmodifiableList(liste) liefert z. B. eine schreibgeschützte “Sicht” auf eine bestehende Liste — nützlich, um eine interne Datenstruktur nach außen zu geben, ohne dass der Aufrufer sie versehentlich verändern kann.
Die Interface-Hierarchie im Überblick
Das Wurzel-Interface Collection<E> wird von drei Hauptzweigen erweitert: List (geordnet, Duplikate erlaubt, Index-Zugriff), Set (keine Duplikate, meist keine garantierte Reihenfolge) und Queue/Deque (FIFO/LIFO-Verhalten für Warteschlangen und Stacks). Map<K, V> gehört technisch NICHT zu Collection (es hat Schlüssel-Wert-Paare statt einzelner Elemente), zählt aber trotzdem zum Collections-Framework dazu:
Deque<String> stapel = new ArrayDeque<>();
stapel.push("erstes");
stapel.push("zweites");
System.out.println(stapel.pop()); // "zweites" - Last In, First Out (Stack-Verhalten)
Queue<String> warteschlange = new LinkedList<>();
warteschlange.offer("erstes");
warteschlange.offer("zweites");
System.out.println(warteschlange.poll()); // "erstes" - First In, First OutTypische Implementierungswahl
Jedes Interface hat mehrere konkrete Implementierungen mit unterschiedlichen Stärken: ArrayList (schneller Index-Zugriff) vs. LinkedList (schnelles Einfügen an den Enden) für List; HashSet (schnellster Zugriff, keine Reihenfolge) vs. TreeSet (sortiert, etwas langsamer) vs. LinkedHashSet (Einfügereihenfolge bleibt erhalten) für Set. Die Wahl hängt fast immer davon ab, welche Operation am häufigsten vorkommt — häufiges Lesen per Index spricht für ArrayList, häufiges Prüfen “ist X schon enthalten?” spricht für HashSet.
Streams als moderne Ergänzung
Seit Java 8 lassen sich Collections elegant mit der Stream-API verarbeiten, statt mit klassischen Schleifen:
List<String> namen = List.of("Anna", "Ben", "Clara");
List<String> grossbuchstaben = namen.stream()
.filter(n -> n.length() > 3)
.map(String::toUpperCase)
.toList();Thread-Sicherheit
Die Standard-Implementierungen (ArrayList, HashMap, HashSet) sind NICHT thread-sicher — mehrere Threads, die gleichzeitig schreibend zugreifen, können die interne Struktur beschädigen oder eine ConcurrentModificationException auslösen. Für nebenläufigen Zugriff gibt es entweder Collections.synchronizedList(liste) (wickelt jede Methode in synchronized ein, einfach aber langsam bei viel Konkurrenz) oder die spezialisierten Klassen aus java.util.concurrent wie ConcurrentHashMap, die intern feingranularer sperren und dadurch deutlich besser skalieren.