Von Elyndra Valen, Senior Entwicklerin bei Java Fleet Systems Consulting
Mit Einblicken von Nova Trent (Junior Dev) und Jamal Hassan (Backend Developer)
Schwierigkeit: 🟢 Einsteiger | 🟡 Mittel
Lesezeit: 30 Minuten
Voraussetzungen: Tag 1 (Listen) abgeschlossen, Java OOP (equals, Interfaces)
Kurs: Java Erweiterte Techniken – Tag 2 von 10
📖 Java Erweiterte Techniken – Alle Tage
📍 Du bist hier: Tag 2
⚡ Das Wichtigste in 30 Sekunden
Dein Problem: Du hast eine Liste von Benutzern und willst Duplikate vermeiden. Oder du brauchst schnellen Zugriff auf Daten per Schlüssel – nicht per Index.
Die Lösung:
- Set – eine Collection, die automatisch Duplikate verhindert
- Map – Key-Value-Paare mit blitzschnellem Zugriff über den Key
Heute lernst du:
- ✅ Wann du Set statt List verwendest
- ✅ HashSet vs. TreeSet vs. LinkedHashSet – und wann welches
- ✅ HashMap als dein neues Lieblings-Tool für Key-Value-Daten
- ✅ Das Geheimnis von
equals()undhashCode()– ohne das Sets und Maps nicht funktionieren! - ✅ Comparable und Comparator für sortierte Collections
Für wen ist dieser Artikel?
- 🌱 Anfänger: Du lernst Sets und Maps von Grund auf
- 🌿 Erfahrene: Du verstehst endlich den equals/hashCode-Vertrag
- 🌳 Profis: TreeSet mit Custom Comparator, NavigableMap-Features
Zeit-Investment: 30 Minuten Lesen + 45-90 Minuten Praxis
👋 Elyndra: „Nova, ich bin stolz auf dich.“
Hi! 👋
Elyndra hier, zurück für Tag 2. Gestern haben wir Listen gemeistert. Heute wird’s spannender.
Letzte Woche hab ich was Schönes beobachtet: Tom, unser Werkstudent, kam zu Nova – komplett frustriert:
Set<Person> personen = new HashSet<>();
personen.add(new Person("Max", "Müller"));
personen.add(new Person("Max", "Müller")); // Duplikat!
System.out.println(personen.size()); // Erwartung: 1
Ausgabe: 2
Tom: „Nova, mein Set ist kaputt! Da sind zwei Max Müller drin!“
Nova hat sich den Code angeschaut – und ich hab gesehen, wie es bei ihr klick gemacht hat. Sie wusste sofort, was los ist. Vor einem Jahr hätte sie noch genauso ratlos dagestanden wie Tom jetzt.
„Tom, zeig mal deine Person-Klasse… Ah. Du hast equals() und hashCode() nicht überschrieben.“
Der Klassiker. Den Fehler macht jeder einmal.
Heute zeige ich dir, wie du diesen Fehler vermeidest – und warum das Verständnis von equals() und hashCode() der Schlüssel zu Sets und Maps ist.
💡 Du kennst Set/Map schon, willst aber equals/hashCode verstehen?
→ Spring direkt zu „Der equals/hashCode-Vertrag“
🖼️ Das Konzept auf einen Blick

Abbildung 1: Set speichert einzigartige Elemente, Map speichert Key-Value-Paare
🟢 GRUNDLAGEN
Was ist ein Set?
Ein Set ist eine Collection, die keine Duplikate erlaubt. Wenn du versuchst, ein Element hinzuzufügen, das schon existiert, passiert einfach… nichts.
Set<String> tags = new HashSet<>();
tags.add("java");
tags.add("programming");
tags.add("java"); // Duplikat – wird ignoriert!
System.out.println(tags.size()); // 2
System.out.println(tags); // [java, programming]
Wann brauchst du ein Set?
| Situation | List oder Set? |
|---|---|
| Einkaufsliste (Reihenfolge wichtig) | List |
| Unique Tags für einen Artikel | Set |
| Playlist (gleicher Song mehrfach möglich) | List |
| Bereits besuchte URLs (keine Duplikate) | Set |
| Benutzer-IDs die online sind | Set |
💬 Nova fragt: „Aber woher weiß das Set, ob etwas ein Duplikat ist?“
Gute Frage! Bei Strings und primitiven Wrappern (Integer, etc.) funktioniert es automatisch. Bei eigenen Klassen musst du Java sagen, wann zwei Objekte „gleich“ sind – mit equals() und hashCode(). Dazu kommen wir gleich!
Die drei Set-Implementierungen

Abbildung 2: HashSet, LinkedHashSet und TreeSet im Vergleich
1. HashSet – Der Schnelle (Standard)
Set<String> hashSet = new HashSet<>();
hashSet.add("Banane");
hashSet.add("Apfel");
hashSet.add("Orange");
System.out.println(hashSet); // [Banane, Orange, Apfel] – KEINE garantierte Reihenfolge!
Eigenschaften:
- ✅ Schnellste Implementierung: O(1) für add, remove, contains
- ✅ Dein Standard-Set für die meisten Fälle
- ❌ Keine garantierte Reihenfolge
2. LinkedHashSet – Der mit Gedächtnis
Set<String> linkedHashSet = new LinkedHashSet<>();
linkedHashSet.add("Banane");
linkedHashSet.add("Apfel");
linkedHashSet.add("Orange");
System.out.println(linkedHashSet); // [Banane, Apfel, Orange] – Einfüge-Reihenfolge!
Eigenschaften:
- ✅ Behält die Einfüge-Reihenfolge
- ✅ Fast so schnell wie HashSet
- ❌ Etwas mehr Speicherverbrauch
3. TreeSet – Der Sortierte
Set<String> treeSet = new TreeSet<>();
treeSet.add("Banane");
treeSet.add("Apfel");
treeSet.add("Orange");
System.out.println(treeSet); // [Apfel, Banane, Orange] – Alphabetisch sortiert!
Eigenschaften:
- ✅ Automatisch sortiert
- ✅ Bietet zusätzliche Methoden:
first(),last(),headSet(),tailSet() - ❌ Langsamer: O(log n) statt O(1)
- ⚠️ Elemente müssen
Comparablesein (oder du gibst einenComparator)
Was ist eine Map?
Eine Map speichert Key-Value-Paare. Du greifst auf Werte über ihren Schlüssel zu – nicht über einen Index.
Map<String, Integer> alter = new HashMap<>();
alter.put("Max", 25);
alter.put("Anna", 30);
alter.put("Tom", 22);
System.out.println(alter.get("Anna")); // 30
System.out.println(alter.get("Lisa")); // null (nicht vorhanden)
Wichtig: Keys müssen eindeutig sein! Wenn du denselben Key nochmal verwendest, wird der alte Wert überschrieben:
alter.put("Max", 25);
alter.put("Max", 26); // Überschreibt den alten Wert!
System.out.println(alter.get("Max")); // 26
Wann brauchst du eine Map?
| Situation | Datenstruktur |
|---|---|
| Telefonbuch: Name → Nummer | Map |
| Konfiguration: Key → Value | Map |
| Wortfrequenz zählen | Map |
| HTTP-Header | Map |
| Cache: ID → Objekt | Map |
Die drei Map-Implementierungen
| Implementierung | Reihenfolge | Performance | Wann verwenden? |
|---|---|---|---|
| HashMap | Keine | O(1) | Standard – 90% der Fälle |
| LinkedHashMap | Einfüge-Reihenfolge | O(1) | Wenn Reihenfolge wichtig |
| TreeMap | Sortiert nach Key | O(log n) | Wenn sortiert nach Key nötig |
// HashMap – keine garantierte Reihenfolge Map<String, Integer> hashMap = new HashMap<>(); // LinkedHashMap – behält Einfüge-Reihenfolge Map<String, Integer> linkedHashMap = new LinkedHashMap<>(); // TreeMap – sortiert nach Key Map<String, Integer> treeMap = new TreeMap<>();
Wichtige Map-Methoden
Map<String, Integer> scores = new HashMap<>();
// Hinzufügen
scores.put("Alice", 100);
scores.put("Bob", 85);
// Abrufen
int aliceScore = scores.get("Alice"); // 100
int unknownScore = scores.getOrDefault("Eve", 0); // 0 (statt null)
// Prüfen
boolean hasAlice = scores.containsKey("Alice"); // true
boolean has100 = scores.containsValue(100); // true
// Entfernen
scores.remove("Bob");
// Alle Keys, alle Values, alle Einträge
Set<String> namen = scores.keySet();
Collection<Integer> punkte = scores.values();
Set<Map.Entry<String, Integer>> entries = scores.entrySet();
// Durch Map iterieren
for (Map.Entry<String, Integer> entry : scores.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
// Oder mit forEach (Java 8+)
scores.forEach((name, score) -> System.out.println(name + ": " + score));
💬 Nova: „Das
getOrDefault()ist nice! Kein null-Check mehr nötig.“
Genau! Und es gibt noch mehr solcher Convenience-Methoden. Dazu kommen wir in der Professionals-Sektion.
🟡 PROFESSIONALS
Der equals/hashCode-Vertrag
Das ist DER wichtigste Abschnitt dieses Artikels. Wenn du nur eine Sache mitnimmst, dann diese.
💬 Jamal: „Real talk: Ich hab in Code Reviews mehr Bugs durch falsches equals/hashCode gesehen als durch fast alles andere. Das hier ist kein Nice-to-know – das ist essential.“
Das Problem (nochmal)
public class Person {
private String vorname;
private String nachname;
public Person(String vorname, String nachname) {
this.vorname = vorname;
this.nachname = nachname;
}
// KEIN equals() und hashCode() überschrieben!
}
Set<Person> personen = new HashSet<>();
personen.add(new Person("Max", "Müller"));
personen.add(new Person("Max", "Müller"));
System.out.println(personen.size()); // 2 – FALSCH!
Warum passiert das?
Ohne überschriebenes equals() verwendet Java die Standardimplementierung von Object: Zwei Objekte sind nur gleich, wenn sie dieselbe Referenz haben (also dasselbe Objekt im Speicher sind).
Person p1 = new Person("Max", "Müller");
Person p2 = new Person("Max", "Müller");
System.out.println(p1 == p2); // false – verschiedene Objekte
System.out.println(p1.equals(p2)); // false – ohne Override: wie ==
Die Lösung: equals() und hashCode() überschreiben
public class Person {
private String vorname;
private String nachname;
public Person(String vorname, String nachname) {
this.vorname = vorname;
this.nachname = nachname;
}
@Override
public boolean equals(Object o) {
// 1. Identität: Bin ich dasselbe Objekt?
if (this == o) return true;
// 2. Null-Check und Typ-Check
if (o == null || getClass() != o.getClass()) return false;
// 3. Cast und Feldvergleich
Person person = (Person) o;
return Objects.equals(vorname, person.vorname)
&& Objects.equals(nachname, person.nachname);
}
@Override
public int hashCode() {
return Objects.hash(vorname, nachname);
}
}
Jetzt funktioniert es:
Set<Person> personen = new HashSet<>();
personen.add(new Person("Max", "Müller"));
personen.add(new Person("Max", "Müller"));
System.out.println(personen.size()); // 1 – RICHTIG!
Der Vertrag (die Regeln)
Diese Regeln MÜSSEN eingehalten werden:
- Konsistenz:
equals()muss bei gleichen Werten immer dasselbe Ergebnis liefern - Symmetrie: Wenn
a.equals(b), dann muss auchb.equals(a)gelten - Transitivität: Wenn
a.equals(b)undb.equals(c), dann mussa.equals(c)gelten - Null-Sicherheit:
a.equals(null)muss immerfalsesein - hashCode-Konsistenz: Wenn
a.equals(b), dann MUSSa.hashCode() == b.hashCode()sein!
⚠️ Die goldene Regel:
Wenn duequals()überschreibst, MUSST du auchhashCode()überschreiben!
Warum? HashSet und HashMap verwenden hashCode() um zu entscheiden, in welchen „Bucket“ ein Element gehört. Erst danach wird equals() aufgerufen.

Abbildung 3: Wie HashSet Elemente speichert und findet
Wenn zwei gleiche Objekte unterschiedliche hashCodes haben, landen sie in verschiedenen Buckets – und das Set findet sie nie als Duplikate!
Best Practices für equals/hashCode
1. Nutze Objects.equals() und Objects.hash():
// ✅ Sicher und lesbar
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return Objects.equals(vorname, person.vorname)
&& Objects.equals(nachname, person.nachname);
}
@Override
public int hashCode() {
return Objects.hash(vorname, nachname);
}
2. Lass die IDE es generieren:
In IntelliJ: Alt + Insert → „equals() and hashCode()“ In NetBeans: Alt + Insert → „equals() and hashCode()…“ In Eclipse: Source → „Generate hashCode() and equals()“
3. Verwende dieselben Felder in beiden Methoden:
// ❌ FALSCH: unterschiedliche Felder
public boolean equals(Object o) {
// vergleicht vorname UND nachname
}
public int hashCode() {
return Objects.hash(vorname); // nur vorname!
}
// ✅ RICHTIG: gleiche Felder
public boolean equals(Object o) {
// vergleicht vorname UND nachname
}
public int hashCode() {
return Objects.hash(vorname, nachname); // beide!
}
📚 Auffrischung nötig?
→ Java OOP Kurs, Tag 3: Datenkapselung (Getter/Setter, Object-Methoden)
Comparable und Comparator
Für TreeSet und TreeMap müssen Elemente sortierbar sein. Dafür gibt es zwei Wege:
1. Comparable – „Ich weiß selbst, wie ich sortiert werde“
Implementiere Comparable<T> in deiner Klasse:
public class Person implements Comparable<Person> {
private String vorname;
private String nachname;
// ... Constructor, equals, hashCode ...
@Override
public int compareTo(Person other) {
// Erst nach Nachname, dann nach Vorname
int nachnameCompare = this.nachname.compareTo(other.nachname);
if (nachnameCompare != 0) {
return nachnameCompare;
}
return this.vorname.compareTo(other.vorname);
}
}
Set<Person> sortiertePersonen = new TreeSet<>();
sortiertePersonen.add(new Person("Max", "Müller"));
sortiertePersonen.add(new Person("Anna", "Schmidt"));
sortiertePersonen.add(new Person("Tom", "Müller"));
// Ausgabe: [Max Müller, Tom Müller, Anna Schmidt]
// (Erst alle Müller, dann Schmidt – alphabetisch)
Rückgabewert von compareTo:
< 0: this kommt VOR other0: gleich> 0: this kommt NACH other
2. Comparator – „Externe Sortierlogik“
Wenn du die Klasse nicht ändern kannst oder verschiedene Sortierungen brauchst:
// Nach Vorname sortieren
Comparator<Person> nachVorname = (p1, p2) -> p1.getVorname().compareTo(p2.getVorname());
Set<Person> nachVornameSortiert = new TreeSet<>(nachVorname);
// Oder mit Comparator-Factory-Methoden (eleganter):
Comparator<Person> nachNachnameDannVorname =
Comparator.comparing(Person::getNachname)
.thenComparing(Person::getVorname);
Set<Person> sortiert = new TreeSet<>(nachNachnameDannVorname);
💬 Nova: „Wann Comparable, wann Comparator?“
Faustregeln:
- Comparable: Wenn es EINE natürliche Sortierung gibt (z.B. Datum chronologisch)
- Comparator: Wenn du mehrere Sortierungen brauchst oder die Klasse nicht ändern kannst
Häufige Stolperfallen
1. Mutable Keys in HashMap
// ❌ GEFÄHRLICH!
List<String> key = new ArrayList<>();
key.add("A");
Map<List<String>, String> map = new HashMap<>();
map.put(key, "Wert");
System.out.println(map.get(key)); // "Wert"
key.add("B"); // Key verändert!
System.out.println(map.get(key)); // null – VERLOREN!
Problem: Wenn du den Key veränderst, ändert sich sein hashCode. Die Map findet ihn nicht mehr.
Lösung: Verwende nur immutable Keys (String, Integer, etc.) oder ändere Keys nie nach dem Einfügen.
2. put() vs. putIfAbsent()
Map<String, Integer> counts = new HashMap<>();
// ❌ Überschreibt existierenden Wert
counts.put("java", 1);
counts.put("java", 2); // Überschreibt!
// ✅ Nur einfügen wenn nicht vorhanden
counts.putIfAbsent("python", 1);
counts.putIfAbsent("python", 2); // Wird ignoriert
3. computeIfAbsent() für komplexe Initialisierung
// Szenario: Map von Listen aufbauen
Map<String, List<String>> gruppiert = new HashMap<>();
// ❌ Umständlich
String key = "gruppe1";
if (!gruppiert.containsKey(key)) {
gruppiert.put(key, new ArrayList<>());
}
gruppiert.get(key).add("Element");
// ✅ Elegant mit computeIfAbsent
gruppiert.computeIfAbsent(key, k -> new ArrayList<>()).add("Element");
🔵 BONUS
NavigableSet und NavigableMap
TreeSet und TreeMap implementieren NavigableSet/NavigableMap mit zusätzlichen Methoden:
TreeSet<Integer> zahlen = new TreeSet<>(List.of(1, 3, 5, 7, 9)); // Nächstkleinerer Wert System.out.println(zahlen.lower(5)); // 3 System.out.println(zahlen.floor(5)); // 5 (inklusive) // Nächstgrößerer Wert System.out.println(zahlen.higher(5)); // 7 System.out.println(zahlen.ceiling(5)); // 5 (inklusive) // Teilmengen System.out.println(zahlen.headSet(5)); // [1, 3] System.out.println(zahlen.tailSet(5)); // [5, 7, 9] System.out.println(zahlen.subSet(3, 7)); // [3, 5] // Erstes/Letztes entfernen System.out.println(zahlen.pollFirst()); // 1 (entfernt) System.out.println(zahlen.pollLast()); // 9 (entfernt)
Performance-Vergleich
| Operation | HashSet | TreeSet | LinkedHashSet |
|---|---|---|---|
| add() | O(1) | O(log n) | O(1) |
| remove() | O(1) | O(log n) | O(1) |
| contains() | O(1) | O(log n) | O(1) |
| Iteration | O(n) | O(n) | O(n) |
| Speicher | Mittel | Hoch | Hoch |
| Operation | HashMap | TreeMap | LinkedHashMap |
|---|---|---|---|
| put() | O(1) | O(log n) | O(1) |
| get() | O(1) | O(log n) | O(1) |
| remove() | O(1) | O(log n) | O(1) |
| containsKey() | O(1) | O(log n) | O(1) |
💬 Jamal: „In 95% der Fälle ist HashMap die richtige Wahl. TreeMap nur wenn du wirklich sortierte Keys brauchst – und das ist seltener als man denkt.“
EnumSet und EnumMap
Für Enums gibt es spezialisierte, hochperformante Implementierungen:
enum Wochentag { MONTAG, DIENSTAG, MITTWOCH, DONNERSTAG, FREITAG, SAMSTAG, SONNTAG }
// EnumSet – extrem schnell für Enum-Elemente
Set<Wochentag> arbeitstage = EnumSet.range(Wochentag.MONTAG, Wochentag.FREITAG);
Set<Wochentag> wochenende = EnumSet.of(Wochentag.SAMSTAG, Wochentag.SONNTAG);
Set<Wochentag> alleAusserMontag = EnumSet.complementOf(EnumSet.of(Wochentag.MONTAG));
// EnumMap – schnellste Map wenn Key ein Enum ist
Map<Wochentag, String> aktivitaeten = new EnumMap<>(Wochentag.class);
aktivitaeten.put(Wochentag.MONTAG, "Kaffee trinken");
aktivitaeten.put(Wochentag.FREITAG, "Feierabend feiern");
Warum sind die so schnell? Sie nutzen intern Bit-Operationen und Arrays statt Hash-Tabellen.
Immutable Sets und Maps (Java 9+)
// Immutable Set
Set<String> immutableSet = Set.of("A", "B", "C");
// Immutable Map
Map<String, Integer> immutableMap = Map.of(
"eins", 1,
"zwei", 2,
"drei", 3
);
// Für mehr als 10 Einträge:
Map<String, Integer> grosseMap = Map.ofEntries(
Map.entry("eins", 1),
Map.entry("zwei", 2),
// ... beliebig viele
);
// Kopie einer bestehenden Map (immutable)
Map<String, Integer> kopie = Map.copyOf(existierendeMap);
⚠️ Achtung:
Set.of()undMap.of()erlauben keine null-Werte und keine Duplikate bei Keys!
💬 Real Talk: Die Klassiker-Falle
Java Fleet Büro, Freitag 16:45. Tom starrt frustriert auf seinen Bildschirm.
Tom: „Nova, ich dreh durch! Mein Set findet meine Objekte nicht. Ich füge eine Person hinzu und contains() sagt false!“
Nova: schaut auf den Code „Zeig mal deine Person-Klasse… Ah, da ist es. Du hast equals überschrieben, aber nicht hashCode.“
Tom: „Aber ich vergleiche doch mit equals? Warum braucht das Set hashCode?“
Jamal: rollt mit seinem Stuhl rüber „HashSet heißt HASH-Set. Der hashCode entscheidet, in welchem Bucket gesucht wird. Ohne passenden hashCode guckt Java im falschen Bucket – und findet nichts.“
Nova: „Stell dir vor, du suchst in einer Bibliothek ein Buch. Der hashCode ist wie die Regalnummer. Wenn zwei Bücher ‚gleich‘ sind aber verschiedene Regalnummern haben, findest du das Duplikat nie.“
Tom: „Ohhh! Also muss ich IMMER beide überschreiben?“
Jamal: „Immer. Keine Ausnahme. Lass die IDE das generieren – dann kann nichts schiefgehen.“
Tom: tippt kurz „Alt+Insert… equals und hashCode… fertig. Wow, das funktioniert ja jetzt!“
Elyndra: hat vom Nachbartisch zugehört, lächelt „Nova, gut erklärt. Du bist weit gekommen.“
Nova: grinst „Ich hatte eine gute Lehrerin.“
❓ FAQ
Frage 1: Wann nehme ich Set, wann List?
Set wenn:
- Keine Duplikate erlaubt
- Reihenfolge egal (oder sortiert mit TreeSet)
- Schnelle
contains()-Prüfung wichtig
List wenn:
- Duplikate möglich/gewünscht
- Index-Zugriff nötig
- Reihenfolge wichtig
Frage 2: HashMap oder TreeMap?
HashMap (Standard): Wenn du O(1)-Zugriff brauchst und Sortierung egal ist.
TreeMap: Wenn du nach Keys sortiert iterieren musst oder Range-Queries brauchst (subMap, headMap, etc.).
Frage 3: Kann ich null in Sets/Maps speichern?
| Collection | null Key | null Values |
|---|---|---|
| HashSet | ✅ Ein null | – |
| TreeSet | ❌ Nein | – |
| HashMap | ✅ Ein null | ✅ Beliebig viele |
| TreeMap | ❌ Nein | ✅ Ja |
| Set.of() | ❌ Nein | – |
| Map.of() | ❌ Nein | ❌ Nein |
Frage 4: Muss ich bei Records auch equals/hashCode überschreiben?
Nein! Records (ab Java 16) generieren automatisch equals(), hashCode() und toString() basierend auf allen Feldern:
record Person(String vorname, String nachname) {}
// equals und hashCode funktionieren automatisch!
Set<Person> personen = new HashSet<>();
personen.add(new Person("Max", "Müller"));
personen.add(new Person("Max", "Müller"));
System.out.println(personen.size()); // 1 – Korrekt!
Frage 5: Was ist der Unterschied zwischen keySet() und entrySet()?
Map<String, Integer> map = Map.of("A", 1, "B", 2);
// keySet() – nur die Keys
for (String key : map.keySet()) {
Integer value = map.get(key); // Extra Lookup nötig!
}
// entrySet() – Key UND Value zusammen (effizienter!)
for (Map.Entry<String, Integer> entry : map.entrySet()) {
String key = entry.getKey();
Integer value = entry.getValue(); // Kein extra Lookup!
}
💡 Tipp: Wenn du Key UND Value brauchst, nimm
entrySet()– das ist schneller.
Frage 6: Wie zähle ich Vorkommen von Elementen?
List<String> woerter = List.of("java", "python", "java", "kotlin", "java");
// Mit Map manuell
Map<String, Integer> counts = new HashMap<>();
for (String wort : woerter) {
counts.merge(wort, 1, Integer::sum);
}
// {java=3, python=1, kotlin=1}
// Oder mit Streams (Tag 6)
Map<String, Long> counts2 = woerter.stream()
.collect(Collectors.groupingBy(w -> w, Collectors.counting()));
Frage 7: Bernd hat mir gesagt, Hashtable sei sicherer als HashMap?
seufz Bernd meint es gut, aber Hashtable ist Legacy aus Java 1.0. Ja, es ist synchronized – aber das macht es langsamer, nicht „sicherer“.
Für Thread-sichere Maps:
ConcurrentHashMap(moderne Lösung)Collections.synchronizedMap(new HashMap<>())(wenn’s sein muss)
Nicht verwenden: Hashtable, Vector, Stack – das ist Java-Geschichte, kein modernes Java.
🔍 Psst… suchst du „behind the code“ oder „in my feels“? Die Private Logs der Crew findest du, wenn du weißt wo du suchen musst…
Frage 8: Wie kopiere ich ein Set/eine Map?
Set<String> original = new HashSet<>(Set.of("A", "B", "C"));
// Shallow Copy (gleiche Objektreferenzen)
Set<String> kopie1 = new HashSet<>(original);
// Immutable Copy (Java 10+)
Set<String> kopie2 = Set.copyOf(original);
// Für Map:
Map<String, Integer> originalMap = new HashMap<>();
Map<String, Integer> kopieMap = new HashMap<>(originalMap);
Map<String, Integer> immutableKopie = Map.copyOf(originalMap);
📚 Quiz-Lösungen
Die Fragen findest du in der Challenge-Sektion.
Frage 1: 2 – Ohne equals/hashCode-Override sind zwei new Person() verschiedene Objekte.
Frage 2: TreeSet, weil es automatisch sortiert. HashSet hat keine garantierte Reihenfolge.
Frage 3: null – Der Key wurde nach dem put() verändert, sein hashCode ist jetzt anders.
Frage 4: O(1) für HashMap, O(log n) für TreeMap.
Frage 5: Ja! Wenn equals true zurückgibt, MÜSSEN die hashCodes gleich sein.
🎁 Cheat Sheet
🟢 Basics (Zum Nachschlagen)
// Set erstellen
Set<String> set = new HashSet<>(); // Standard
Set<String> ordered = new LinkedHashSet<>(); // Reihenfolge
Set<String> sorted = new TreeSet<>(); // Sortiert
// Set-Operationen
set.add("element");
set.remove("element");
set.contains("element");
set.size();
set.isEmpty();
set.clear();
// Map erstellen
Map<String, Integer> map = new HashMap<>();
Map<String, Integer> ordered = new LinkedHashMap<>();
Map<String, Integer> sorted = new TreeMap<>();
// Map-Operationen
map.put("key", value);
map.get("key");
map.getOrDefault("key", defaultValue);
map.remove("key");
map.containsKey("key");
map.containsValue(value);
map.keySet();
map.values();
map.entrySet();
🟡 Patterns (Für den Alltag)
// equals/hashCode Pattern
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MyClass that = (MyClass) o;
return Objects.equals(field1, that.field1)
&& Objects.equals(field2, that.field2);
}
@Override
public int hashCode() {
return Objects.hash(field1, field2);
}
// Map mit Default-Wert initialisieren
map.computeIfAbsent(key, k -> new ArrayList<>()).add(value);
// Elemente zählen
map.merge(key, 1, Integer::sum);
// Durch Map iterieren
map.forEach((k, v) -> System.out.println(k + ": " + v));
🔵 Advanced (Für Profis)
// Comparator-Chain
Comparator<Person> comparator = Comparator
.comparing(Person::getNachname)
.thenComparing(Person::getVorname)
.reversed();
// NavigableSet-Features
TreeSet<Integer> zahlen = new TreeSet<>();
zahlen.lower(5); // Nächstkleinerer
zahlen.higher(5); // Nächstgrößerer
zahlen.subSet(3, 7); // Range [3, 7)
// EnumSet/EnumMap
Set<Day> workDays = EnumSet.range(Day.MONDAY, Day.FRIDAY);
Map<Day, String> schedule = new EnumMap<>(Day.class);
🎨 Challenge für dich!
Teste dein Wissen!
Quiz-Fragen:
- Was gibt
personen.size()aus, wenn Person KEIN equals/hashCode hat?Set<Person> personen = new HashSet<>(); personen.add(new Person("Max", "Müller")); personen.add(new Person("Max", "Müller")); - Welches Set behält die Sortierung: HashSet, LinkedHashSet oder TreeSet?
- Was gibt dieser Code aus?
List<String> key = new ArrayList<>(); key.add("A"); Map<List<String>, String> map = new HashMap<>(); map.put(key, "Wert"); key.add("B"); System.out.println(map.get(key)); - Was ist die Zeitkomplexität von
get()bei HashMap vs. TreeMap? - Müssen zwei Objekte mit gleichem hashCode auch equals sein?
Praktische Aufgaben:
🟢 Level 1 – Einsteiger
- [ ] Erstelle ein HashSet mit 5 Städtenamen und prüfe ob „Berlin“ enthalten ist
- [ ] Erstelle eine HashMap die Ländernamen auf ihre Hauptstädte mappt Geschätzte Zeit: 15-30 Minuten
🟡 Level 2 – Fortgeschritten
- [ ] Implementiere eine
Student-Klasse mit korrektem equals/hashCode - [ ] Zähle die Worthäufigkeit in einem Text mit HashMap Geschätzte Zeit: 30-60 Minuten
🔵 Level 3 – Profi
- [ ] Implementiere einen LRU-Cache mit LinkedHashMap
- [ ] Erstelle ein TreeSet mit Comparator für Personen (erst Alter, dann Name) Geschätzte Zeit: 1-2 Stunden
📦 Downloads
Alle Code-Beispiele zum Herunterladen:
| Projekt | Für wen? | Download |
|---|---|---|
| tag02-sets-maps-starter.zip | 🟢 Einsteiger | ⬇️ Download |
| tag02-sets-maps-complete.zip | 🟡 Alle Levels | ⬇️ Download |
Quick Start:
# 1. ZIP entpacken unzip tag02-sets-maps-starter.zip # 2. In NetBeans öffnen # Datei → Projekt öffnen → Ordner auswählen # 3. Main.java ausführen # Rechtsklick → Run File
🔗 Weiterführende Links
🇩🇪 Deutsch
| Ressource | Beschreibung |
|---|---|
| Rheinwerk OpenBook: Java SE 8 | Kostenloses Standardwerk, Kapitel Datenstrukturen |
| Javabeginners: HashMap | Grundlagen HashMap/Hashtable |
| straub.as: HashSet erklärt | Bucket-Prinzip auf Deutsch erklärt |
| DelftStack: HashMap vs HashSet | Unterschiede mit Codebeispielen |
🇬🇧 Englisch
| Ressource | Beschreibung | Level |
|---|---|---|
| Oracle Java Tutorials: Collections | Offizielle Dokumentation | 🟢 |
| W3Schools: Java HashSet | Interaktive Beispiele | 🟢 |
| GeeksforGeeks: HashSet | Umfassende Referenz | 🟡 |
| Baeldung: equals() and hashCode() | DER Artikel zum Thema! | 🟡 |
| Baeldung: Guide to hashCode() | Tiefes Verständnis | 🟡 |
| HowToDoInJava: hashCode & equals | Best Practices | 🟡 |
| Baeldung: Records equals/hashCode | Modern: Records ab Java 16 | 🔵 |
🛠️ Tools
| Tool | Beschreibung |
|---|---|
| EqualsVerifier | Automatisches Testen von equals/hashCode |
| IntelliJ: Generate equals/hashCode | IDE-Generator |
📧 Offizielle Dokumentation
👋 Geschafft! 🎉
Was du heute gelernt hast:
✅ Set für einzigartige Elemente – HashSet, TreeSet, LinkedHashSet
✅ Map für Key-Value-Paare – HashMap, TreeMap, LinkedHashMap
✅ Der equals/hashCode-Vertrag – das Fundament für Collections mit eigenen Klassen
✅ Comparable vs. Comparator für Sortierung
✅ Moderne Convenience-Methoden: getOrDefault, computeIfAbsent, merge
Egal ob du heute zum ersten Mal von equals/hashCode gehört hast oder endlich verstanden hast, warum dein Code nicht funktioniert hat – du hast etwas Wichtiges gelernt. Das zählt!
Fragen? Schreib uns:
- elyndra.valen@java-developer.online
- nova.trent@java-developer.online
- jamal.hassan@java-developer.online
📖 Weiter geht’s!
← Vorheriger Tag: Tag 1: Collections – Listen
→ Nächster Tag: Tag 3: Generics
Tags: #Java #Collections #Set #Map #HashSet #HashMap #equals #hashCode
📚 Das könnte dich auch interessieren
© 2025 Java Fleet Systems Consulting | java-developer.online

