Collections (List, Set, Map)
Das Java Collections Framework: ArrayList, HashSet, HashMap und mehr. Dynamische Datenstrukturen für jeden Anwendungsfall.
Collections (List, Set, Map)
Arrays haben eine feste Groesse — das ist unpraktisch. Collections sind dynamische Datenstrukturen, die wachsen und schrumpfen koennen. Das Java Collections Framework bietet fuer jeden Anwendungsfall die passende Struktur.
Ueberblick: Die drei Haupttypen
| Typ | Beschreibung | Duplikate | Reihenfolge | Beispiel |
|---|---|---|---|---|
| List | Geordnete Sammlung | Ja | Ja (Index) | Einkaufsliste |
| Set | Einzigartige Elemente | Nein | Nicht garantiert | E-Mail-Adressen |
| Map | Schluessel-Wert-Paare | Schluessel: Nein | Abhaengig von Implementierung | Telefonbuch |
List — Geordnete Sammlung
ArrayList (am haeufigsten)
import java.util.ArrayList;
import java.util.List;
// Erstellen
var namen = new ArrayList<String>();
namen.add("Max");
namen.add("Anna");
namen.add("Leo");
// Oder kuerzer (unveraenderlich):
var namenFix = List.of("Max", "Anna", "Leo");
// Oder kuerzer (veraenderlich):
var namenFlex = new ArrayList<>(List.of("Max", "Anna", "Leo"));
Wichtige List-Methoden
var liste = new ArrayList<>(List.of("A", "B", "C", "D"));
// Zugriff
liste.get(0); // "A"
liste.size(); // 4
liste.isEmpty(); // false
liste.contains("B"); // true
liste.indexOf("C"); // 2
// Hinzufuegen
liste.add("E"); // Am Ende: [A, B, C, D, E]
liste.add(1, "X"); // An Position 1: [A, X, B, C, D, E]
// Aendern
liste.set(0, "Z"); // Element ersetzen: [Z, X, B, C, D, E]
// Entfernen
liste.remove("X"); // Nach Wert: [Z, B, C, D, E]
liste.remove(0); // Nach Index: [B, C, D, E]
// Durchlaufen
for (var element : liste) {
System.out.println(element);
}
// Sortieren
liste.sort(String::compareTo); // Alphabetisch
liste.sort(String.CASE_INSENSITIVE_ORDER); // Case-insensitive
List.of() vs. new ArrayList
// Unveraenderlich (immutable) -- zum Lesen
var fixListe = List.of("A", "B", "C");
// fixListe.add("D"); // FEHLER! UnsupportedOperationException
// Veraenderlich (mutable) -- zum Aendern
var flexListe = new ArrayList<>(List.of("A", "B", "C"));
flexListe.add("D"); // OK!
Vergleich mit Python
# Python: Listen
namen = ["Max", "Anna", "Leo"]
namen.append("Julia")
namen[0] # "Max"
len(namen) # 4
// Java: ArrayList
var namen = new ArrayList<>(List.of("Max", "Anna", "Leo"));
namen.add("Julia");
namen.get(0); // "Max"
namen.size(); // 4
Set — Einzigartige Elemente
HashSet (am haeufigsten)
import java.util.HashSet;
import java.util.Set;
var fruechte = new HashSet<String>();
fruechte.add("Apfel");
fruechte.add("Banane");
fruechte.add("Apfel"); // Duplikat -- wird ignoriert!
System.out.println(fruechte); // [Banane, Apfel] (keine Reihenfolge!)
System.out.println(fruechte.size()); // 2
// Oder unveraenderlich:
var fixSet = Set.of("Apfel", "Banane", "Kirsche");
Set-Operationen
var setA = new HashSet<>(Set.of(1, 2, 3, 4, 5));
var setB = new HashSet<>(Set.of(4, 5, 6, 7, 8));
// Vereinigung (Union)
var vereinigung = new HashSet<>(setA);
vereinigung.addAll(setB);
System.out.println(vereinigung); // [1, 2, 3, 4, 5, 6, 7, 8]
// Schnittmenge (Intersection)
var schnitt = new HashSet<>(setA);
schnitt.retainAll(setB);
System.out.println(schnitt); // [4, 5]
// Differenz
var differenz = new HashSet<>(setA);
differenz.removeAll(setB);
System.out.println(differenz); // [1, 2, 3]
Wann Set statt List?
// Duplikate aus einer Liste entfernen
var mitDuplikaten = List.of(1, 2, 3, 2, 1, 4, 3, 5);
var ohneDuplikate = new ArrayList<>(new HashSet<>(mitDuplikaten));
System.out.println(ohneDuplikate); // [1, 2, 3, 4, 5]
// Enthaltensein pruefen (Set ist VIEL schneller als List!)
var erlaubteNamen = Set.of("Admin", "Moderator", "User");
if (erlaubteNamen.contains("Admin")) {
System.out.println("Zugang erlaubt!");
}
Map — Schluessel-Wert-Paare
HashMap (am haeufigsten)
import java.util.HashMap;
import java.util.Map;
var telefonbuch = new HashMap<String, String>();
telefonbuch.put("Max", "0171-1234567");
telefonbuch.put("Anna", "0172-2345678");
telefonbuch.put("Leo", "0173-3456789");
// Zugriff
System.out.println(telefonbuch.get("Max")); // 0171-1234567
System.out.println(telefonbuch.get("Julia")); // null (nicht vorhanden)
// Sicherer Zugriff
System.out.println(telefonbuch.getOrDefault("Julia", "Nicht gefunden"));
// Oder unveraenderlich:
var fixMap = Map.of("Max", "0171-1234567", "Anna", "0172-2345678");
Wichtige Map-Methoden
var noten = new HashMap<String, Double>();
noten.put("Mathe", 2.3);
noten.put("Deutsch", 1.7);
noten.put("Englisch", 1.0);
// Grundlegende Operationen
noten.size(); // 3
noten.containsKey("Mathe"); // true
noten.containsValue(1.0); // true
noten.remove("Deutsch"); // Entfernt Eintrag
// Alle Schluessel
noten.keySet(); // [Mathe, Englisch]
// Alle Werte
noten.values(); // [2.3, 1.0]
// Alle Eintraege
noten.entrySet(); // [Mathe=2.3, Englisch=1.0]
// Durchlaufen
for (var eintrag : noten.entrySet()) {
System.out.printf("%s: %.1f%n", eintrag.getKey(), eintrag.getValue());
}
// Oder kompakter
noten.forEach((fach, note) ->
System.out.printf("%s: %.1f%n", fach, note)
);
Haeufigkeitsanalyse mit Map
var text = "hallo welt hallo java welt hallo";
var woerter = text.split(" ");
var haeufigkeit = new HashMap<String, Integer>();
for (var wort : woerter) {
haeufigkeit.merge(wort, 1, Integer::sum);
}
System.out.println(haeufigkeit);
// {hallo=3, java=1, welt=2}
Welche Collection wann?
| Situation | Verwende | Grund |
|---|---|---|
| Geordnete Liste | ArrayList | Index-Zugriff, Reihenfolge |
| Keine Duplikate | HashSet | Einzigartigkeit, schnelles contains() |
| Schluessel-Wert | HashMap | Schneller Zugriff ueber Schluessel |
| Sortierte Liste | ArrayList + sort() | Sortierung nach Bedarf |
| Sortiertes Set | TreeSet | Automatisch sortiert |
| Sortierte Map | TreeMap | Automatisch nach Schluessel sortiert |
| Thread-sicher | ConcurrentHashMap | Mehrere Threads |
| Warteschlange | LinkedList / ArrayDeque | FIFO-Prinzip |
Streams mit Collections
var studenten = List.of(
new Student("Max", 2.3),
new Student("Anna", 1.0),
new Student("Leo", 3.7),
new Student("Julia", 1.3),
new Student("Tom", 4.0)
);
// Filtern
var bestanden = studenten.stream()
.filter(s -> s.note() <= 4.0)
.toList();
// Sortieren
var nachNote = studenten.stream()
.sorted((a, b) -> Double.compare(a.note(), b.note()))
.toList();
// Durchschnitt
var durchschnitt = studenten.stream()
.mapToDouble(Student::note)
.average()
.orElse(0);
// Namen sammeln
var alleNamen = studenten.stream()
.map(Student::name)
.toList();
System.out.println("Bestanden: " + bestanden);
System.out.printf("Durchschnitt: %.1f%n", durchschnitt);
(Hier ist Student ein record Student(String name, double note) {})
Unveraenderliche Collections (Empfohlen)
// Unveraenderlich -- bevorzugen!
var namen = List.of("Max", "Anna", "Leo");
var zahlen = Set.of(1, 2, 3);
var daten = Map.of("key1", "val1", "key2", "val2");
// Kopie einer veraenderlichen Collection als unveraenderlich
var original = new ArrayList<>(List.of("A", "B", "C"));
var kopie = List.copyOf(original);
Uebungen
Uebung 1: Einkaufsliste
Erstelle eine Einkaufsliste mit ArrayList. Implementiere Methoden zum Hinzufuegen, Entfernen, Sortieren und Anzeigen.
Uebung 2: Wort-Zaehler
Lies einen Text ein und zaehle, wie oft jedes Wort vorkommt (mit HashMap). Sortiere die Ergebnisse nach Haeufigkeit.
Uebung 3: Kontaktbuch
Erstelle ein Kontaktbuch (Map<String, Kontakt>) mit Suche, Hinzufuegen und Loeschen.
Uebung 4: Lotterie
Generiere 6 einzigartige Zufallszahlen (1-49) mit einem HashSet und sortiere sie.
Was kommt als Naechstes?
In der naechsten Lektion lernst du Generics — damit kannst du eigene typsichere Collections und Klassen erstellen.
Zusammenfassung
- List (
ArrayList): Geordnet, Duplikate erlaubt, Index-Zugriff - Set (
HashSet): Keine Duplikate, schnellescontains() - Map (
HashMap): Schluessel-Wert-Paare, schneller Zugriff List.of(),Set.of(),Map.of()erstellen unveraenderliche Collections- Streams ermoeglichen funktionale Operationen (filter, map, reduce)
- Bevorzuge unveraenderliche Collections, wenn moeglich
ArrayListist die meistverwendete Collection in Java
Pro-Tipp: Deklariere deine Variablen immer mit dem Interface-Typ statt dem konkreten Typ: List<String> namen = new ArrayList<>() statt ArrayList<String> namen = new ArrayList<>(). So kannst du die Implementierung spaeter austauschen, ohne den Rest des Codes aendern zu muessen. Das ist ein wichtiges Designprinzip: “Programmiere gegen Schnittstellen, nicht gegen Implementierungen.”