/
/
·
·
/
/
·
·
  • Einführung
  • Die Idee in einem Satz
  • Die 3 Familien im Überblick
  • List, die geordnete Liste
  • Set, die duplikatfreie Sammlung
  • Map, die Schlüssel-Wert-Zuordnung
  • Iteration: die for-each-[Schleife](/themen/schleifen)
  • Wichtige Implementierungen
  • Beispiel: Wann was?
  • Klausur-Faustregeln
  • Klausur-Beispielaufgabe
  • Häufige Stolpersteine
ThemenProgrammiergrundlagenCollections-Framework
Programmiergrundlagen·4Lerneinheiten·39min·Stand17.07.2026

Collections-Framework.

Collections-Framework (List, Set, Map)

Du brauchst eine Datenstruktur, deren Größe sich zur Laufzeit ändert? Das Java-Collections-Framework liefert dir dafür 3 große Familien: List (geordnete Reihenfolge, Duplikate erlaubt), Set (keine Duplikate), Map (Key-Value-Zuordnung). Sie sind das Brot-und-Butter-Werkzeug in jedem Java-Programm, vom Warenkorb über eindeutige Tags bis zum Telefonbuch. Die richtige Wahl zwischen List, Set und Map ist nicht nur Stil: sie entscheidet, ob unerwünschte Duplikate entstehen, ob eine Suche in O(1) oder O(n) läuft, und ob deine Reihenfolge erhalten bleibt. Genau deshalb ist sie in Klausuren und in echtem Code so zentral. Du lernst hier die drei Familien, ihre wichtigsten Operationen, die Default-Implementierungen ArrayList / HashSet / HashMap, die sortierten Tree-Varianten und die typischen Klausur-Fallen (Index auf Set, null in TreeMap, equals/hashCode bei eigenen Klassen, ConcurrentModificationException).

Typische Klausurfrage: "Wann List, wann Set, wann Map?" zusammen mit den jeweiligen Operationen.

Big-O kurz: O(1) heißt konstante Zeit, unabhängig von der Größe (gleich schnell bei 10 oder 10 Mio. Elementen). O(log n) wächst langsam mit, O(n) linear (doppelt so viele Elemente, doppelt so lange). Diese drei Klassen reichen für die ganze Collections-Diskussion.

Wähle die Datenstruktur nach deiner Frage: Brauchst du die Reihenfolge? → List. Willst du Duplikate verhindern? → Set. Brauchst du einen Schlüssel-Lookup (Wert unter Schlüssel)? → Map.

FamilieReihenfolgeDuplikateLookup-SchlüsselWichtigster Vertreter
List<E>ja (Index 0, 1, 2 ...)jaIndex (int)ArrayList<E>
Set<E>normalerweise neinneinkein Index/Key, contains(e) bei HashSet O(1)HashSet<E>
Map<K, V>–Werte ja, Keys neinKey (K)HashMap<K, V>
List  [0]   [1]   [2]   [3]        Zugriff über Index, Reihenfolge fest
      "A"   "B"   "A"   "C"        Duplikate ("A" doppelt) erlaubt

Set   { "A" , "B" , "C" }         kein Index, keine Reihenfolge-Garantie
      add("A") zum 2. Mal -> ignoriert (Filter), Frage: contains?

Map   "Anna" -> 1                 Schlüssel -> Wert, Schlüssel eindeutig
      "Ben"  -> 3                 get("Anna") liefert 1

Visuell ausprobieren: Im Interaktiv-Tab kannst du genau diese drei Strukturen mit identischen Operationen nebeneinander durchspielen, und darunter zerlegen drei Code-Stepper (je einer für List, Set, Map) jede Operation Schritt für Schritt, genau dort setzt die typische Klausur-Tracing-Aufgabe an.

Verwende List wenn: du Items in einer bestimmten Reihenfolge speichern willst und Duplikate erlaubt sind.

Index:    0       1       2
        ┌───────┬───────┬───────┐
namen   │ Anna  │  Ben  │ Anna  │   get(1) -> "Ben", Duplikat "Anna" ok
        └───────┴───────┴───────┘
import java.util.ArrayList;
import java.util.List;

List<String> namen = new ArrayList<>();
namen.add("Anna");
namen.add("Ben");
namen.add("Anna");  // Duplikat ist ok

System.out.println(namen);     // [Anna, Ben, Anna]
System.out.println(namen.size());     // 3
System.out.println(namen.get(1));     // Ben
namen.remove(0);
System.out.println(namen);     // [Ben, Anna]

Wichtigste Operationen:

  • add(e), hinten anfügen (bei ArrayList amortisiert O(1))
  • add(i, e), an Index i einfügen (am Anfang O(n), weil alle folgenden Elemente verschoben werden)
  • get(i), Element holen (bei ArrayList O(1), direkter Index-Zugriff)
  • set(i, e), Element ersetzen
  • remove(i), Element löschen (am Anfang O(n) wegen Verschiebung)
  • size(), Anzahl
  • contains(e), enthält? (O(n)!)
  • indexOf(e), erster Index

Genau hinschauen: Bei ArrayList ist nur der reine Index-Zugriff get(i) konstant (O(1)). Einfügen oder Löschen am Anfang ist O(n), weil dahinter alles eine Position weiterrutschen muss. add(e) ohne Index hängt hinten an und ist deshalb schnell.

Verwende Set wenn: du nur prüfen willst, ob etwas vorkommt, und Duplikate egal sind (sollen weg).

add("java")  ──►  ┌─────────────────────┐
add("oop")   ──►  │  { "java" , "oop" }  │   contains("oop")? -> true (O(1))
add("java")  ──►  └─────────────────────┘   2. "java" wird vom Filter
                   Duplikat-Filter             abgewiesen, size bleibt 2
import java.util.HashSet;
import java.util.Set;

Set<String> tags = new HashSet<>();
tags.add("java");
tags.add("oop");
tags.add("java");  // Duplikat wird ignoriert!

System.out.println(tags.size());            // 2
System.out.println(tags.contains("oop"));   // true (sehr schnell, O(1))

Wichtigste Operationen:

  • add(e), hinzufügen (true wenn neu)
  • contains(e), enthält? (O(1) bei HashSet)
  • remove(e), entfernen
  • size()
  • Kein get(i)! Sets haben keinen Index und keinen Key. Du fragst nicht "gib mir Element Nr. 3", sondern "ist Element e drin?" über contains(e) (bei HashSet typischerweise O(1)).

Achtung bei eigenen Klassen: Ob ein Set ein Element als Duplikat erkennt, entscheidet es über equals() und hashCode(). Eigene Klassen (z. B. Student) musst du diese beiden Methoden überschreiben lassen, sonst werden Objekte nur per Referenz verglichen, und zwei Student-Objekte mit gleichem Inhalt landen beide im Set. Mehr dazu unter "Häufige Stolpersteine".

HashSet vs. TreeSet: HashSet ist unsortiert, sehr schnell (durchschnittlich O(1) für add/contains bei guter Hash-Verteilung). TreeSet ist sortiert (alphabetisch / numerisch), aber langsamer (garantiert O(log n)). Ein weiterer Unterschied: HashSet erlaubt ein null-Element, TreeSet mit natürlicher Ordnung (Comparable) wirft beim Einfügen von null eine NullPointerException (es müsste null sortieren, was nicht geht).

Verwende Map wenn: du Werte unter einem Schlüssel ablegen willst, also das Telefonbuch-Prinzip (Name → Nummer).

        Schlüssel (Key)        Wert (Value)
        ┌───────────┐          ┌───┐
        │  "Anna"   │ ───────► │ 1 │   put("Anna", 2) überschreibt -> 2
        ├───────────┤          ├───┤
        │  "Ben"    │ ───────► │ 3 │   get("Ben") -> 3
        └───────────┘          └───┘
        Keys eindeutig         Werte dürfen sich wiederholen
import java.util.HashMap;
import java.util.Map;

Map<String, Integer> noten = new HashMap<>();
noten.put("Anna", 1);
noten.put("Ben", 3);
noten.put("Anna", 2);  // ersetzt Annas alte Note!

System.out.println(noten.get("Anna"));      // 2
System.out.println(noten.containsKey("Ben")); // true
System.out.println(noten.size());           // 2

Wichtigste Operationen:

  • put(k, v), Wert unter Key speichern (überschreibt)
  • get(k), Wert holen (null wenn nicht da)
  • containsKey(k), Key vorhanden?
  • remove(k), Eintrag löschen
  • keySet(), alle Keys als Set
  • values(), alle Werte als Collection
  • entrySet(), alle Key-Value-Paare
// List
for (String name : namen) {
    System.out.println(name);
}

// Set
for (String tag : tags) {
    System.out.println(tag);
}

// Map
for (Map.Entry<String, Integer> eintrag : noten.entrySet()) {
    System.out.println(eintrag.getKey() + " = " + eintrag.getValue());
}

Klausur-Frage: "Was passiert wenn du während des for-each-Loops strukturell Elemente entfernst?" → Das ist unzulässig und löst typischerweise eine ConcurrentModificationException aus. Wichtig: Diese Prüfung ist best-effort, also nicht garantiert. Je nach Position kann derselbe Loop sogar ohne Exception durchlaufen (klassischer Fall: du entfernst das vorletzte Element) und liefert dann still ein falsches Ergebnis, was noch gefährlicher ist als ein Absturz. Merke: Verlass dich nie darauf, dass es kracht, modifiziere einfach nie während des for-each. Lösung: Iterator explizit nutzen oder removeIf(...). Letzteres ist die kürzeste sichere Variante:

// UNZULAESSIG: modifiziert die Liste waehrend des for-each.
// Wirft MEIST eine ConcurrentModificationException, aber best-effort:
// je nach Position kann es auch still durchlaufen (= versteckter Bug).
for (String name : namen) {
    if (name.equals("Ben")) namen.remove(name);
}

// SAFE: removeIf nimmt ein Predicate und entfernt intern korrekt
namen.removeIf(name -> name.equals("Ben"));
InterfaceImplementierungCharakteristik
ListArrayListdynamisches Array, Index-Zugriff get(i) O(1), Insert/Remove am Anfang O(n)
ListLinkedListdoppelt-verkettete Liste, Insert/Remove an Anfang/Ende O(1), in der Mitte O(n) (Traversierung)
SetHashSetHash-basiert, schnell (O(1)), unsortiert
SetTreeSetrot-schwarz-Baum, sortiert, O(log n)
SetLinkedHashSetwie HashSet aber merkt Einfüge-Reihenfolge
MapHashMapHash-basiert, schnell (O(1)), unsortiert
MapTreeMaprot-schwarz-Baum, nach Keys sortiert
MapLinkedHashMapwie HashMap aber Einfüge-Reihenfolge

ArrayList vs. LinkedList (Klausur-Klassiker): ArrayList ist am Ende schnell und am Anfang langsam (O(n) durch Verschieben), aber get(i) ist O(1). LinkedList ist umgekehrt: schnelles Insert/Remove an Anfang und Ende (O(1)), aber get(i) in der Mitte ist O(n), weil die Liste von vorne durchlaufen werden muss. Im Zweifel ArrayList: der schnelle Index-Zugriff überwiegt fast immer.

Daumenregel: Wenn unsicher → ArrayList, HashSet, HashMap. Die sind 90% aller Fälle die richtige Wahl.

ProblemDatenstrukturBegründung
Bestellte Items im WarenkorbListReihenfolge zählt, Duplikate (2x dasselbe Buch) ok
Eindeutige Tags eines PostsSetDuplikate sinnlos, schnelle "enthält?"-Abfrage
User-ID → User-ObjektMapSchlüssel-Lookup
Eindeutige Email-AdressenSetEmail kann nur 1x vorkommen
Top-10-BestsellerListReihenfolge IST die Information
Wörter alphabetischTreeSetsortiert + duplikatfrei

1. List = geordnet + Duplikate. Set = duplikatfrei. Map = Key→Value. Ende.

2. ArrayList ist Default-List. HashMap ist Default-Map. HashSet ist Default-Set. Spezialisierte Implementierungen erst wenn du einen Grund hast.

3. Hash-Implementierungen sind durchschnittlich O(1) für add/contains/get (bei guter Hash-Verteilung; Worst-Case schlechter). Tree-Implementierungen sind O(log n). Listen sind O(n) für contains.

4. null als Wert/Key, genau differenzieren:

  • HashSet erlaubt ein null-Element (mehr nicht, ist ja duplikatfrei).
  • HashMap erlaubt einen null-Key und beliebig viele null-Values (mehrere Keys dürfen auf null zeigen).
  • TreeSet / TreeMap mit natürlicher Ordnung (Comparable) werfen beim Einfügen von null (Element bzw. Key) eine NullPointerException, weil null nicht sortierbar ist. (Ausnahme: ein eigens geschriebener null-fähiger Comparator, kein Klausur-Standard.)

5. equals und hashCode müssen konsistent sein wenn du eigene Klassen in Sets/Maps speicherst. Sonst tauchen Objekte mehrfach auf oder werden nicht gefunden.

Beispiel (typischer Klausur-Stil, zur Übung konstruiert, keine reale Klausur).

Eine Bibliothek-Anwendung soll drei Daten verwalten. Ordne jeder Anforderung die passende Collection (List, Set oder Map) plus eine konkrete Implementierung zu und begründe kurz:

  1. Die Ausleih-Historie eines Nutzers (jedes ausgeliehene Buch, in zeitlicher Reihenfolge, dasselbe Buch darf mehrfach vorkommen).
  2. Die Menge der ISBN-Nummern, die aktuell im Bestand sind (jede ISBN höchstens einmal, schnelle "ist X im Bestand?"-Abfrage).
  3. Die Zuordnung Nutzer-ID → Nutzer-Objekt für schnellen Zugriff per ID.

Zusatzfrage: Bei einem Bestand von 10.000 ISBNs, welche Laufzeit hat die Abfrage "ist diese ISBN im Bestand?" in deiner Lösung, und wie viele Operationen fallen worst-case an, wenn man stattdessen eine ArrayList verwendet hätte?

Lösungsschritte:

  1. Ausleih-Historie → List, konkret ArrayList<Buch>. Begründung: Reihenfolge ist Teil der Information (chronologisch) und Duplikate sind erlaubt (dasselbe Buch mehrfach ausgeliehen). Damit fallen Set (verbietet Duplikate) und Map (braucht Schlüssel) aus. (Deckt der Abschnitt "List, die geordnete Liste".)
  2. ISBN-Bestand → Set, konkret HashSet<String>. Begründung: jede ISBN höchstens einmal (Duplikat-Freiheit) und es wird nur "enthält?" gefragt, kein Index und kein Wert nötig. HashSet liefert contains(isbn) in O(1). (Deckt der Abschnitt "Set, die duplikatfreie Sammlung".)
  3. Nutzer-ID → Nutzer → Map, konkret HashMap<Integer, Nutzer>. Begründung: klassischer Schlüssel-Lookup, get(id) liefert das Objekt in O(1). (Deckt der Abschnitt "Map, die Schlüssel-Wert-Zuordnung".)
  4. Laufzeit der ISBN-Abfrage (bei 10.000 ISBNs): mit HashSet ist contains durchschnittlich O(1), also unabhängig von der Bestandsgröße ungefähr konstant wenige Schritte. Mit einer ArrayList wäre dieselbe Abfrage O(n): worst-case müssen alle 10.000 Einträge durchgegangen werden (das gesuchte Element ganz hinten oder gar nicht vorhanden). Genau dieser Unterschied (konstant vs. bis zu 10.000 Vergleiche) ist die typische Begründung, warum man hier Set statt List nimmt. (Deckt die Abschnitte "Wichtige Implementierungen" und "Klausur-Faustregeln".)

1. Set mit Index zugreifen. set.get(0) gibt's nicht. Wenn du Index brauchst → List.

2. map.get(key) ohne Null-Check. Wenn Key nicht da → null zurück. Ein NullPointerException bei der nächsten Operation ist garantiert. Lösung: containsKey vorher oder getOrDefault.

3. Collections.sort(set) versuchen. Set ist nicht sortiert (ausser TreeSet). sort funktioniert nur auf List. Wenn du eine sortierte Reihenfolge willst: new ArrayList<>(set) und dann sortieren.

4. Eigene Objekte in HashSet/HashMap ohne equals/hashCode override. Standard-equals vergleicht Referenzen, nicht Inhalt. Zwei Student-Objekte mit gleichem Namen sind dann "verschieden". Lösung: equals und hashCode überschreiben.

5. ConcurrentModificationException beim Iterieren + Entfernen. Niemals in einem for-each-Loop collection.remove(...) aufrufen. Lösung: removeIf(predicate) oder expliziter Iterator mit it.remove().

3 identische Operationen, ausgeführt auf List, Set, Map gleichzeitig. Beobachte die Unterschiede.

Wähle eine Operation aus und sieh, was bei jeder Datenstruktur passiert. So merkst du dir Reihenfolge / Duplikate / Lookup-Verhalten ohne auswendig zu lernen.

Beispiel-Operationen: add("java"), add("java") (zweites Mal), contains("java"), size(). Achte darauf, wie das Set das zweite "java" abweist (size bleibt 1), die List es brav als Duplikat aufnimmt (size 2), und die Map dafür einen Key braucht statt eines reinen Werts.

Lade Visualisierung...

Klausur-Tipp: Bei Klausurfragen zur Datenstruktur-Wahl frag dich: (1) Ist die Reihenfolge wichtig? → List. (2) Sind Duplikate ok? Wenn nein → Set. (3) Brauche ich Lookup über einen Schlüssel? → Map. In 90% aller Fälle reicht diese Entscheidungslogik.


Drei interaktive Demos, je eine pro Familie. Klick Step oder Auto und beobachte, wie sich die Datenstruktur, ihre Größe und die Konsole pro Operation verändern. Genau dieser Verlauf wird in Klausuren als Tracing-Aufgabe abgefragt.

1. List (ArrayList): Reihenfolge bleibt, Duplikate erlaubt

add hängt hinten an, get(1) greift über den Index zu, remove(0) löscht das erste Element und alles rückt nach.

Lade Visualisierung...

2. Set (HashSet): Duplikat-Filter in Aktion

Das dritte add("java") ist ein Duplikat und wird stillschweigend abgewiesen. size() bleibt deshalb bei 2, und contains ist die typische Set-Frage.

Lade Visualisierung...

3. Map (HashMap): put überschreibt bei gleichem Key

Der zweite put("Anna", ...) legt keinen neuen Eintrag an, sondern überschreibt Annas Wert, weil Keys eindeutig sind. get auf einen fehlenden Key liefert null.

Lade Visualisierung...

Anmelden, um den Fortschritt zu speichern.

Nächster Schritt

Wenn du fertig bist: jetzt üben.

Aktives Abrufen festigt Wissen schneller als nochmal lesen.

War das hilfreich?

Verwandte Themen

  • Variablen und Datentypen
  • Bedingungen
  • Schleifen
  • Funktionen
  • Rekursion

Folgt

  • Lambdas & Higher-Order-Funktionen
  • Streams und Collectors

Tools

Bald: Karteikarten · Spaced-Repetition · Mind-Map-Export

Fachliche Qualität
S-Tier · GoldstandardZuletzt geprüft am 12.06.2026

Diese Lerneinheit wurde für typische Bachelor-Klausuren konzipiert. So prüfen wir · Fehler entdeckt? Melde ihn uns oder markiere die fragliche Stelle direkt im Text oben.

Klausur-ÜbersichtKomplette Übersicht: alle Tabs als linearer Text zum Lernen
▾

Alle Tabs der Lerneinheit (Erklärung · Interaktiv verstehen · Praxis-Übung · Klausur-Quiz) als durchgehender Text. Ideal zum Wiederholen vor der Klausur, und für Suchmaschinen wie Google, Bing und KI-Suche (ChatGPT, Perplexity).

Inhalt dieser Übersicht

  1. Erklärung(Erklärung)
  2. Interaktiv verstehen(Visualisierung / Interaktiv)
  3. Praxis-Übung(Quiz / Klausurfragen)
  4. Klausur-Quiz(Quiz / Klausurfragen)
Teil 1·Erklärung

Erklärung

Collections-Framework (List, Set, Map)

Du brauchst eine Datenstruktur, deren Größe sich zur Laufzeit ändert? Das Java-Collections-Framework liefert dir dafür 3 große Familien: List (geordnete Reihenfolge, Duplikate erlaubt), Set (keine Duplikate), Map (Key-Value-Zuordnung). Sie sind das Brot-und-Butter-Werkzeug in jedem Java-Programm, vom Warenkorb über eindeutige Tags bis zum Telefonbuch. Die richtige Wahl zwischen List, Set und Map ist nicht nur Stil: sie entscheidet, ob unerwünschte Duplikate entstehen, ob eine Suche in O(1) oder O(n) läuft, und ob deine Reihenfolge erhalten bleibt. Genau deshalb ist sie in Klausuren und in echtem Code so zentral. Du lernst hier die drei Familien, ihre wichtigsten Operationen, die Default-Implementierungen ArrayList / HashSet / HashMap, die sortierten Tree-Varianten und die typischen Klausur-Fallen (Index auf Set, null in TreeMap, equals/hashCode bei eigenen Klassen, ConcurrentModificationException).

Typische Klausurfrage: "Wann List, wann Set, wann Map?" zusammen mit den jeweiligen Operationen.

Big-O kurz: O(1) heißt konstante Zeit, unabhängig von der Größe (gleich schnell bei 10 oder 10 Mio. Elementen). O(log n) wächst langsam mit, O(n) linear (doppelt so viele Elemente, doppelt so lange). Diese drei Klassen reichen für die ganze Collections-Diskussion.

Die Idee in einem Satz

Wähle die Datenstruktur nach deiner Frage: Brauchst du die Reihenfolge? → List. Willst du Duplikate verhindern? → Set. Brauchst du einen Schlüssel-Lookup (Wert unter Schlüssel)? → Map.

Die 3 Familien im Überblick

FamilieReihenfolgeDuplikateLookup-SchlüsselWichtigster Vertreter
List<E>ja (Index 0, 1, 2 ...)jaIndex (int)ArrayList<E>
Set<E>normalerweise neinneinkein Index/Key, contains(e) bei HashSet O(1)HashSet<E>
Map<K, V>–Werte ja, Keys neinKey (K)HashMap<K, V>
List  [0]   [1]   [2]   [3]        Zugriff über Index, Reihenfolge fest
      "A"   "B"   "A"   "C"        Duplikate ("A" doppelt) erlaubt

Set   { "A" , "B" , "C" }         kein Index, keine Reihenfolge-Garantie
      add("A") zum 2. Mal -> ignoriert (Filter), Frage: contains?

Map   "Anna" -> 1                 Schlüssel -> Wert, Schlüssel eindeutig
      "Ben"  -> 3                 get("Anna") liefert 1

Visuell ausprobieren: Im Interaktiv-Tab kannst du genau diese drei Strukturen mit identischen Operationen nebeneinander durchspielen, und darunter zerlegen drei Code-Stepper (je einer für List, Set, Map) jede Operation Schritt für Schritt, genau dort setzt die typische Klausur-Tracing-Aufgabe an.

List, die geordnete Liste

Verwende List wenn: du Items in einer bestimmten Reihenfolge speichern willst und Duplikate erlaubt sind.

Index:    0       1       2
        ┌───────┬───────┬───────┐
namen   │ Anna  │  Ben  │ Anna  │   get(1) -> "Ben", Duplikat "Anna" ok
        └───────┴───────┴───────┘
import java.util.ArrayList;
import java.util.List;

List<String> namen = new ArrayList<>();
namen.add("Anna");
namen.add("Ben");
namen.add("Anna");  // Duplikat ist ok

System.out.println(namen);     // [Anna, Ben, Anna]
System.out.println(namen.size());     // 3
System.out.println(namen.get(1));     // Ben
namen.remove(0);
System.out.println(namen);     // [Ben, Anna]

Wichtigste Operationen:

  • add(e), hinten anfügen (bei ArrayList amortisiert O(1))
  • add(i, e), an Index i einfügen (am Anfang O(n), weil alle folgenden Elemente verschoben werden)
  • get(i), Element holen (bei ArrayList O(1), direkter Index-Zugriff)
  • set(i, e), Element ersetzen
  • remove(i), Element löschen (am Anfang O(n) wegen Verschiebung)
  • size(), Anzahl
  • contains(e), enthält? (O(n)!)
  • indexOf(e), erster Index

Genau hinschauen: Bei ArrayList ist nur der reine Index-Zugriff get(i) konstant (O(1)). Einfügen oder Löschen am Anfang ist O(n), weil dahinter alles eine Position weiterrutschen muss. add(e) ohne Index hängt hinten an und ist deshalb schnell.

Set, die duplikatfreie Sammlung

Verwende Set wenn: du nur prüfen willst, ob etwas vorkommt, und Duplikate egal sind (sollen weg).

add("java")  ──►  ┌─────────────────────┐
add("oop")   ──►  │  { "java" , "oop" }  │   contains("oop")? -> true (O(1))
add("java")  ──►  └─────────────────────┘   2. "java" wird vom Filter
                   Duplikat-Filter             abgewiesen, size bleibt 2
import java.util.HashSet;
import java.util.Set;

Set<String> tags = new HashSet<>();
tags.add("java");
tags.add("oop");
tags.add("java");  // Duplikat wird ignoriert!

System.out.println(tags.size());            // 2
System.out.println(tags.contains("oop"));   // true (sehr schnell, O(1))

Wichtigste Operationen:

  • add(e), hinzufügen (true wenn neu)
  • contains(e), enthält? (O(1) bei HashSet)
  • remove(e), entfernen
  • size()
  • Kein get(i)! Sets haben keinen Index und keinen Key. Du fragst nicht "gib mir Element Nr. 3", sondern "ist Element e drin?" über contains(e) (bei HashSet typischerweise O(1)).

Achtung bei eigenen Klassen: Ob ein Set ein Element als Duplikat erkennt, entscheidet es über equals() und hashCode(). Eigene Klassen (z. B. Student) musst du diese beiden Methoden überschreiben lassen, sonst werden Objekte nur per Referenz verglichen, und zwei Student-Objekte mit gleichem Inhalt landen beide im Set. Mehr dazu unter "Häufige Stolpersteine".

HashSet vs. TreeSet: HashSet ist unsortiert, sehr schnell (durchschnittlich O(1) für add/contains bei guter Hash-Verteilung). TreeSet ist sortiert (alphabetisch / numerisch), aber langsamer (garantiert O(log n)). Ein weiterer Unterschied: HashSet erlaubt ein null-Element, TreeSet mit natürlicher Ordnung (Comparable) wirft beim Einfügen von null eine NullPointerException (es müsste null sortieren, was nicht geht).

Map, die Schlüssel-Wert-Zuordnung

Verwende Map wenn: du Werte unter einem Schlüssel ablegen willst, also das Telefonbuch-Prinzip (Name → Nummer).

        Schlüssel (Key)        Wert (Value)
        ┌───────────┐          ┌───┐
        │  "Anna"   │ ───────► │ 1 │   put("Anna", 2) überschreibt -> 2
        ├───────────┤          ├───┤
        │  "Ben"    │ ───────► │ 3 │   get("Ben") -> 3
        └───────────┘          └───┘
        Keys eindeutig         Werte dürfen sich wiederholen
import java.util.HashMap;
import java.util.Map;

Map<String, Integer> noten = new HashMap<>();
noten.put("Anna", 1);
noten.put("Ben", 3);
noten.put("Anna", 2);  // ersetzt Annas alte Note!

System.out.println(noten.get("Anna"));      // 2
System.out.println(noten.containsKey("Ben")); // true
System.out.println(noten.size());           // 2

Wichtigste Operationen:

  • put(k, v), Wert unter Key speichern (überschreibt)
  • get(k), Wert holen (null wenn nicht da)
  • containsKey(k), Key vorhanden?
  • remove(k), Eintrag löschen
  • keySet(), alle Keys als Set
  • values(), alle Werte als Collection
  • entrySet(), alle Key-Value-Paare

Iteration: die for-each-Schleife

// List
for (String name : namen) {
    System.out.println(name);
}

// Set
for (String tag : tags) {
    System.out.println(tag);
}

// Map
for (Map.Entry<String, Integer> eintrag : noten.entrySet()) {
    System.out.println(eintrag.getKey() + " = " + eintrag.getValue());
}

Klausur-Frage: "Was passiert wenn du während des for-each-Loops strukturell Elemente entfernst?" → Das ist unzulässig und löst typischerweise eine ConcurrentModificationException aus. Wichtig: Diese Prüfung ist best-effort, also nicht garantiert. Je nach Position kann derselbe Loop sogar ohne Exception durchlaufen (klassischer Fall: du entfernst das vorletzte Element) und liefert dann still ein falsches Ergebnis, was noch gefährlicher ist als ein Absturz. Merke: Verlass dich nie darauf, dass es kracht, modifiziere einfach nie während des for-each. Lösung: Iterator explizit nutzen oder removeIf(...). Letzteres ist die kürzeste sichere Variante:

// UNZULAESSIG: modifiziert die Liste waehrend des for-each.
// Wirft MEIST eine ConcurrentModificationException, aber best-effort:
// je nach Position kann es auch still durchlaufen (= versteckter Bug).
for (String name : namen) {
    if (name.equals("Ben")) namen.remove(name);
}

// SAFE: removeIf nimmt ein Predicate und entfernt intern korrekt
namen.removeIf(name -> name.equals("Ben"));

Wichtige Implementierungen

InterfaceImplementierungCharakteristik
ListArrayListdynamisches Array, Index-Zugriff get(i) O(1), Insert/Remove am Anfang O(n)
ListLinkedListdoppelt-verkettete Liste, Insert/Remove an Anfang/Ende O(1), in der Mitte O(n) (Traversierung)
SetHashSetHash-basiert, schnell (O(1)), unsortiert
SetTreeSetrot-schwarz-Baum, sortiert, O(log n)
SetLinkedHashSetwie HashSet aber merkt Einfüge-Reihenfolge
MapHashMapHash-basiert, schnell (O(1)), unsortiert
MapTreeMaprot-schwarz-Baum, nach Keys sortiert
MapLinkedHashMapwie HashMap aber Einfüge-Reihenfolge

ArrayList vs. LinkedList (Klausur-Klassiker): ArrayList ist am Ende schnell und am Anfang langsam (O(n) durch Verschieben), aber get(i) ist O(1). LinkedList ist umgekehrt: schnelles Insert/Remove an Anfang und Ende (O(1)), aber get(i) in der Mitte ist O(n), weil die Liste von vorne durchlaufen werden muss. Im Zweifel ArrayList: der schnelle Index-Zugriff überwiegt fast immer.

Daumenregel: Wenn unsicher → ArrayList, HashSet, HashMap. Die sind 90% aller Fälle die richtige Wahl.

Beispiel: Wann was?

ProblemDatenstrukturBegründung
Bestellte Items im WarenkorbListReihenfolge zählt, Duplikate (2x dasselbe Buch) ok
Eindeutige Tags eines PostsSetDuplikate sinnlos, schnelle "enthält?"-Abfrage
User-ID → User-ObjektMapSchlüssel-Lookup
Eindeutige Email-AdressenSetEmail kann nur 1x vorkommen
Top-10-BestsellerListReihenfolge IST die Information
Wörter alphabetischTreeSetsortiert + duplikatfrei

Klausur-Faustregeln

1. List = geordnet + Duplikate. Set = duplikatfrei. Map = Key→Value. Ende.

2. ArrayList ist Default-List. HashMap ist Default-Map. HashSet ist Default-Set. Spezialisierte Implementierungen erst wenn du einen Grund hast.

3. Hash-Implementierungen sind durchschnittlich O(1) für add/contains/get (bei guter Hash-Verteilung; Worst-Case schlechter). Tree-Implementierungen sind O(log n). Listen sind O(n) für contains.

4. null als Wert/Key, genau differenzieren:

  • HashSet erlaubt ein null-Element (mehr nicht, ist ja duplikatfrei).
  • HashMap erlaubt einen null-Key und beliebig viele null-Values (mehrere Keys dürfen auf null zeigen).
  • TreeSet / TreeMap mit natürlicher Ordnung (Comparable) werfen beim Einfügen von null (Element bzw. Key) eine NullPointerException, weil null nicht sortierbar ist. (Ausnahme: ein eigens geschriebener null-fähiger Comparator, kein Klausur-Standard.)

5. equals und hashCode müssen konsistent sein wenn du eigene Klassen in Sets/Maps speicherst. Sonst tauchen Objekte mehrfach auf oder werden nicht gefunden.

Klausur-Beispielaufgabe

Beispiel (typischer Klausur-Stil, zur Übung konstruiert, keine reale Klausur).

Eine Bibliothek-Anwendung soll drei Daten verwalten. Ordne jeder Anforderung die passende Collection (List, Set oder Map) plus eine konkrete Implementierung zu und begründe kurz:

  1. Die Ausleih-Historie eines Nutzers (jedes ausgeliehene Buch, in zeitlicher Reihenfolge, dasselbe Buch darf mehrfach vorkommen).
  2. Die Menge der ISBN-Nummern, die aktuell im Bestand sind (jede ISBN höchstens einmal, schnelle "ist X im Bestand?"-Abfrage).
  3. Die Zuordnung Nutzer-ID → Nutzer-Objekt für schnellen Zugriff per ID.

Zusatzfrage: Bei einem Bestand von 10.000 ISBNs, welche Laufzeit hat die Abfrage "ist diese ISBN im Bestand?" in deiner Lösung, und wie viele Operationen fallen worst-case an, wenn man stattdessen eine ArrayList verwendet hätte?

Lösungsschritte:

  1. Ausleih-Historie → List, konkret ArrayList<Buch>. Begründung: Reihenfolge ist Teil der Information (chronologisch) und Duplikate sind erlaubt (dasselbe Buch mehrfach ausgeliehen). Damit fallen Set (verbietet Duplikate) und Map (braucht Schlüssel) aus. (Deckt der Abschnitt "List, die geordnete Liste".)
  2. ISBN-Bestand → Set, konkret HashSet<String>. Begründung: jede ISBN höchstens einmal (Duplikat-Freiheit) und es wird nur "enthält?" gefragt, kein Index und kein Wert nötig. HashSet liefert contains(isbn) in O(1). (Deckt der Abschnitt "Set, die duplikatfreie Sammlung".)
  3. Nutzer-ID → Nutzer → Map, konkret HashMap<Integer, Nutzer>. Begründung: klassischer Schlüssel-Lookup, get(id) liefert das Objekt in O(1). (Deckt der Abschnitt "Map, die Schlüssel-Wert-Zuordnung".)
  4. Laufzeit der ISBN-Abfrage (bei 10.000 ISBNs): mit HashSet ist contains durchschnittlich O(1), also unabhängig von der Bestandsgröße ungefähr konstant wenige Schritte. Mit einer ArrayList wäre dieselbe Abfrage O(n): worst-case müssen alle 10.000 Einträge durchgegangen werden (das gesuchte Element ganz hinten oder gar nicht vorhanden). Genau dieser Unterschied (konstant vs. bis zu 10.000 Vergleiche) ist die typische Begründung, warum man hier Set statt List nimmt. (Deckt die Abschnitte "Wichtige Implementierungen" und "Klausur-Faustregeln".)

Häufige Stolpersteine

1. Set mit Index zugreifen. set.get(0) gibt's nicht. Wenn du Index brauchst → List.

2. map.get(key) ohne Null-Check. Wenn Key nicht da → null zurück. Ein NullPointerException bei der nächsten Operation ist garantiert. Lösung: containsKey vorher oder getOrDefault.

3. Collections.sort(set) versuchen. Set ist nicht sortiert (ausser TreeSet). sort funktioniert nur auf List. Wenn du eine sortierte Reihenfolge willst: new ArrayList<>(set) und dann sortieren.

4. Eigene Objekte in HashSet/HashMap ohne equals/hashCode override. Standard-equals vergleicht Referenzen, nicht Inhalt. Zwei Student-Objekte mit gleichem Namen sind dann "verschieden". Lösung: equals und hashCode überschreiben.

5. ConcurrentModificationException beim Iterieren + Entfernen. Niemals in einem for-each-Loop collection.remove(...) aufrufen. Lösung: removeIf(predicate) oder expliziter Iterator mit it.remove().

Teil 2·Visualisierung / Interaktiv

Interaktiv verstehen

Collections-Vergleichs-Visualizer

3 identische Operationen, ausgeführt auf List, Set, Map gleichzeitig. Beobachte die Unterschiede.

Wähle eine Operation aus und sieh, was bei jeder Datenstruktur passiert. So merkst du dir Reihenfolge / Duplikate / Lookup-Verhalten ohne auswendig zu lernen.

Beispiel-Operationen: add("java"), add("java") (zweites Mal), contains("java"), size(). Achte darauf, wie das Set das zweite "java" abweist (size bleibt 1), die List es brav als Duplikat aufnimmt (size 2), und die Map dafür einen Key braucht statt eines reinen Werts.

Interaktive Visualisierung

Interaktive Komponente: probiere sie im Topic-Player oben aus.

Klausur-Tipp: Bei Klausurfragen zur Datenstruktur-Wahl frag dich: (1) Ist die Reihenfolge wichtig? → List. (2) Sind Duplikate ok? Wenn nein → Set. (3) Brauche ich Lookup über einen Schlüssel? → Map. In 90% aller Fälle reicht diese Entscheidungslogik.


Code-Stepper: Schritt für Schritt durchspielen

Drei interaktive Demos, je eine pro Familie. Klick Step oder Auto und beobachte, wie sich die Datenstruktur, ihre Größe und die Konsole pro Operation verändern. Genau dieser Verlauf wird in Klausuren als Tracing-Aufgabe abgefragt.

1. List (ArrayList): Reihenfolge bleibt, Duplikate erlaubt

add hängt hinten an, get(1) greift über den Index zu, remove(0) löscht das erste Element und alles rückt nach.

Interaktive Visualisierung

Interaktive Komponente: probiere sie im Topic-Player oben aus.

2. Set (HashSet): Duplikat-Filter in Aktion

Das dritte add("java") ist ein Duplikat und wird stillschweigend abgewiesen. size() bleibt deshalb bei 2, und contains ist die typische Set-Frage.

Interaktive Visualisierung

Interaktive Komponente: probiere sie im Topic-Player oben aus.

3. Map (HashMap): put überschreibt bei gleichem Key

Der zweite put("Anna", ...) legt keinen neuen Eintrag an, sondern überschreibt Annas Wert, weil Keys eindeutig sind. get auf einen fehlenden Key liefert null.

Interaktive Visualisierung

Interaktive Komponente: probiere sie im Topic-Player oben aus.

Teil 3·Quiz / Klausurfragen

Praxis-Übung

Collections, Praxis-Übung

6 Aufgaben zur Wahl der richtigen Datenstruktur und ihren Operationen.

Klausurfragen mit Lösungen (6)

F1.Du sollst alle Tags eines Blog-Posts speichern. Tags sind eindeutig. Welche Datenstruktur?

Antwort: HashSet<String>

Erklärung: Set, eindeutige Werte ohne Reihenfolge-Bedeutung. HashSet ist die Default-Wahl: schnelles add/contains, automatisch duplikatfrei. ArrayList würde Duplikate erlauben, HashMap braucht Keys, Stack wäre LIFO-Reihenfolge.

F2.Du sollst Student-Objekte unter ihrer Matrikelnummer (Integer) ablegen, um schnell darauf zugreifen zu können. Welche Datenstruktur?

Antwort: HashMap<Integer, Student>

Erklärung: Map<Integer, Student>, die Matrikelnummer ist der Schlüssel, das Student-Objekt der Wert. studenten.get(12345) liefert in O(1) den passenden Studenten. ArrayList wäre O(n) Suche, Set ohne Index sinnlos.

F3.Ein HashSet behält die Reihenfolge, in der Elemente eingefügt wurden.

Antwort: Falsch

Erklärung: FALSCH. HashSet hat KEINE definierte Reihenfolge, Hashcode-basierte Anordnung intern, oft anders als Einfüge-Reihenfolge. Wenn du Einfüge-Reihenfolge brauchst: LinkedHashSet. Wenn sortiert: TreeSet.

Typ: Wahr/Falsch

F4.Bei map.put("Anna", 1) und danach map.put("Anna", 2) enthält die Map zwei Einträge.

Antwort: Falsch

Erklärung: FALSCH. put mit existierendem Key überschreibt den alten Wert. Map.size() = 1, map.get("Anna") = 2. Keys in Maps sind eindeutig, wenn du mehrere Werte unter einem Key willst: Map<String, List<Integer>>.

Typ: Wahr/Falsch

F5.Welche Aussagen über das Collections-Framework sind RICHTIG?

Richtige Antworten: ArrayList erlaubt Duplikate; Set hat keine get(i)-Methode; HashMap erlaubt null als Key; List.add(e) hängt am Ende an

Erklärung: Richtig: ArrayList erlaubt Duplikate, Set hat keinen Index, HashMap erlaubt 1x null als Key, List.add hängt hinten an. Falsch: HashSet ist duplikatfrei (Definition!), TreeSet ist sortiert (nicht unsortiert).

Typ: Multi-Select

F6.Ordne Problem ↔ beste Datenstruktur:

Zuordnungen:

  • Warenkorb (Reihenfolge, Duplikate ok) → ArrayList
  • Eindeutige Tags eines Posts → HashSet
  • Telefonbuch Name → Nummer → HashMap
  • Wörter alphabetisch + eindeutig → TreeSet

Erklärung: Standard-Entscheidungs-Vokabular. Reihenfolge → List, Eindeutigkeit → Set, Lookup → Map, sortiert + eindeutig → TreeSet.

Typ: Zuordnung

Teil 4·Quiz / Klausurfragen

Klausur-Quiz

Klausurfragen mit Lösungen (7)

F1.Welche Laufzeit-Komplexität hat contains(e) bei einem HashSet?

Antwort: O(1) durchschnittlich

Erklärung: HashSet nutzt Hash-Tabelle: contains ist durchschnittlich O(1) bei guter Hash-Verteilung (Worst-Case O(n) bei Hash-Kollisionen). 'Amortisiert' passt eher zu add wegen der Resize-Kosten, nicht zu contains. TreeSet wäre O(log n), ArrayList O(n) wegen linearer Suche.

F2.Eine ArrayList hat 5 Elemente. Du fügst mit add() 2 weitere hinzu und entfernst danach mit remove(0) ein Element. Was liefert size()?

Antwort: 6

Erklärung: 5 + 2 = 7, dann nimmt remove(0) genau ein Element raus → 6. Jeder add()-Aufruf erhöht size um 1, jeder erfolgreiche remove() senkt sie um 1. Die Position spielt für size() keine Rolle.

Typ: Zahlen-Eingabe

F3.Was ist beim strukturellen Entfernen während eines for-each-Loops über eine ArrayList das Problem?

Antwort: Meist eine ConcurrentModificationException (best-effort, nicht garantiert)

Erklärung: Strukturelles Ändern während des for-each ist unzulässig und löst typischerweise eine ConcurrentModificationException aus, allerdings nur best-effort: je nach Position kann es auch still durchlaufen und ein falsches Ergebnis liefern. Beides ist falsch. Lösung: Iterator mit it.remove() oder list.removeIf(predicate).

F4.TreeMap und TreeSet mit natürlicher Ordnung (ohne null-fähigen Comparator) werfen NullPointerException, wenn man null als Key/Element einfügt.

Antwort: Wahr

Erklärung: RICHTIG. Tree-Implementierungen müssen vergleichen (sortieren). Bei natürlicher Ordnung (Comparable) lässt sich null nicht vergleichen → NullPointerException beim Einfügen. Nur ein eigens geschriebener null-fähiger Comparator könnte das umgehen (kein Klausur-Standard). HashMap und HashSet erlauben dagegen 1x null.

Typ: Wahr/Falsch

F5.Du hast eigene Klasse Student mit Feld int matrnr. Du fügst zwei Student-Objekte mit identischer matrnr in ein HashSet ein. Wie viele Elemente sind drin?

Antwort: 1, wenn equals() und hashCode() überschrieben sind, sonst 2

Erklärung: Standard-equals vergleicht REFERENZEN, nicht Inhalt. Zwei verschiedene Student-Instanzen sind technisch verschieden → beide landen im Set. Damit HashSet sie als gleich erkennt, MUSST du equals() UND hashCode() überschreiben (Vertrag: gleich → gleicher hashCode).

F6.List behält die {{1}} und erlaubt {{2}}. Set ist {{3}}. Map ordnet einem {{4}} einen Wert zu. Die Default-Implementierung für eine schnelle Map ist {{5}}.

Lösungen pro Lücke:

  • {{1}}: Reihenfolge / Einfüge-Reihenfolge
  • {{2}}: Duplikate / Duplicates
  • {{3}}: duplikatfrei / duplikat-frei / ohne Duplikate
  • {{4}}: Schlüssel / Key
  • {{5}}: HashMap

Erklärung: Kern-Vokabular der 3 Collections. List = Reihenfolge + Duplikate. Set = duplikatfrei. Map = Key→Value. HashMap = Default für Maps.

Typ: Lückentext

F7.Sortiere die Schritte zum sicheren Iterieren-und-Entfernen einer ArrayList:

Richtige Reihenfolge:

  1. Iterator<E> it = liste.iterator();
  2. while (it.hasNext()) { ... }
  3. E element = it.next();
  4. if (sollGeloeschtWerden(element))
  5. it.remove(); // sicher!

Erklärung: Iterator-Pattern für sicheres Entfernen. it.remove() ist erlaubt, list.remove() im for-each wäre ConcurrentModificationException. Alternative: list.removeIf(predicate) in einer Zeile.

Typ: Reihenfolge

Zur KategorieProgrammiergrundlagen.Mehr Themen entdeckenZum Themen-Hub.

UniProMax ist eine themenbasierte Lernplattform für Studierende an deutschen Unis.

Wir glauben, dass Verstehen besser ist als Auswendiglernen. Wir bauen Lerneinheiten die zeigen statt erzählen. Code, Visualisierung, Quiz. Auf Deutsch.

Marke

UniProMaxUniProMax

Themenbasiert, visuell, interaktiv.

Inhalte

  • Alle Themen (Hub)
  • Programmiergrundlagen
  • Algorithmen
  • Mathematik
  • Statistik
  • Datenbanken
  • Rechnungswesen
  • VWL

Studiengang-Filter

  • Informatik
  • Wirtschaftsinformatik
  • BWL
  • Data Science
  • VWL
  • Wirtschaftsingenieurwesen
  • Mathe
  • Psychologie
  • weitere Studiengänge folgen

Plattform

  • Mein Fortschritt
  • Impressum
  • Datenschutz
© 2026 UniProMaxAlle Systeme onlinev0.2 / Sommersemester 2026
UniProMaxUniProMaxUniProMaxUniProMax