1. Einleitung
Im realen Leben treffen wir oft Situationen, in denen jedem eindeutigen „Schlüssel“ ein „Wert“ zugeordnet werden muss. Ein Telefonbuch speichert Telefonnummer und Namen, ein Wörterbuch verknüpft ein Wort mit seiner Übersetzung, und in einer Notentabelle hat jeder Studierende seinen Namen und die entsprechende Punktzahl.
In Java gibt es für solche Aufgaben die Schnittstelle Map. Sie ist eine Sammlung, die Paare „Schlüssel – Wert“ (key-value pair) speichert.
Wesentliche Eigenschaften von Map:
- Jeder Schlüssel ist eindeutig (Duplikate sind nicht erlaubt).
- Zu einem Schlüssel kann es nur genau einen Wert geben.
- Werte dürfen sich wiederholen.
Stellen wir uns eine Analogie vor. Wenn eine Liste (List) wie eine Schlange in der Mensa ist (jede Person hat ihre Position, Zugriff per Index), dann ist eine Map (Map) wie ein Schließfach mit Fächern: Jedes Fach hat eine Nummer (Schlüssel), und darin liegt etwas Eigenes (Wert).
Schnittstelle Map: grundlegende Operationen
Die Schnittstelle Map deklariert die wichtigsten Methoden zum Arbeiten mit Schlüssel-Wert-Paaren:
| Methode | Beschreibung |
|---|---|
|
Wert für Schlüssel hinzufügen/ersetzen |
|
Wert per Schlüssel abrufen |
|
Paar per Schlüssel entfernen |
|
Prüfen, ob ein Schlüssel existiert |
|
Prüfen, ob ein Wert existiert |
|
Anzahl der Paare in der Map |
|
Prüfen, ob die Map leer ist |
|
Alle Paare entfernen |
Die Typen K und V sind Generics: K (Key) – Typ des Schlüssels, V (Value) – Typ des Werts.
3. Klasse HashMap: schneller Zugriff per Schlüssel
Was ist eine HashMap?
HashMap ist die populärste Implementierung der Schnittstelle Map. Sie ermöglicht schnellen Zugriff auf Werte über den Schlüssel.
Wichtig: HashMap garantiert keine Speicherreihenfolge der Elemente! Auch wenn Sie Schlüssel in einer bestimmten Reihenfolge hinzufügen, kann die Iteration eine andere Reihenfolge liefern.
Wie erstellt man eine HashMap?
import java.util.HashMap;
import java.util.Map;
public class Example {
public static void main(String[] args) {
// Wir erstellen eine Map: Schlüssel – String, Wert – Integer
Map<String, Integer> ages = new HashMap<>();
// Elemente hinzufügen
ages.put("John", 25);
ages.put("Peter", 30);
ages.put("Mary", 22);
// Wert per Schlüssel abrufen
int johnAge = ages.get("John");
System.out.println("Alter von John: " + johnAge); // 25
// Auf das Vorhandensein eines Schlüssels prüfen
if (ages.containsKey("Mary")) {
System.out.println("Mary ist in der Liste!");
}
// Element entfernen
ages.remove("Peter");
// Alle Schlüssel-Wert-Paare durchlaufen
for (String name : ages.keySet()) {
System.out.println(name + ": " + ages.get(name));
}
}
}
Ausgabe:
Alter von John: 25
Mary ist in der Liste!
John: 25
Mary: 22
Besonderheiten von HashMap
Das Wichtigste, das man sich merken sollte: Schlüssel in HashMap sind stets eindeutig. Wenn Sie ein neues Element mit einem schon vorhandenen Schlüssel ablegen, wird der alte Wert durch den neuen ersetzt.
Werte dürfen sich wiederholen: Mehrere unterschiedliche Schlüssel können auf denselben Wert zeigen.
Und noch ein wichtiger Punkt – die Reihenfolge der Elemente. HashMap kümmert sich nicht um die Einfügereihenfolge. Beim Ausgeben können die Einträge „durchmischt“ erscheinen – das ist das normale Verhalten.
4. Klasse TreeMap: Sortierung nach Schlüssel
Im Gegensatz zur HashMap speichert die Klasse TreeMap die Elemente in sortierter Reihenfolge nach dem Schlüssel.
Wann sollte man TreeMap verwenden?
Wenn es wichtig ist, dass die Elemente nach aufsteigenden (oder absteigenden) Schlüsseln geordnet sind. Zum Beispiel, wenn Sie ein Telefonbuch alphabetisch ausgeben möchten.
Beispiel:
import java.util.Map;
import java.util.TreeMap;
public class TreeMapExample {
public static void main(String[] args) {
Map<String, String> phoneBook = new TreeMap<>();
phoneBook.put("John", "+1-900-123-45-67");
phoneBook.put("Mary", "+1-900-555-55-55");
phoneBook.put("Peter", "+1-900-222-33-44");
for (String name : phoneBook.keySet()) {
System.out.println(name + ": " + phoneBook.get(name));
}
}
}
Ausgabe:
Mary: +1-900-555-55-55
Peter: +1-900-222-33-44
John: +1-900-123-45-67
Beachten Sie: Die Schlüssel sind alphabetisch sortiert.
5. Grundlegende Operationen mit Map
Hinzufügen und Ersetzen von Einträgen
Map<String, Integer> scores = new HashMap<>();
scores.put("Anna", 90);
scores.put("Robert", 85);
scores.put("Anna", 95); // Überschreibt den Wert für "Anna"
Wert abrufen
Integer annaScore = scores.get("Anna"); // 95
Integer unknown = scores.get("John"); // null, falls es keinen solchen Schlüssel gibt
Prüfen auf Schlüssel oder Wert
scores.containsKey("Robert"); // true
scores.containsValue(85); // true
Eintrag per Schlüssel entfernen
scores.remove("Robert");
Größe der Map und Leeren
int size = scores.size();
scores.clear(); // Entfernt alle Einträge
5. Elemente einer Map durchlaufen
Map ist keine Liste; es gibt keine Indizes. Man kann aber iterieren:
Über die Schlüssel:
for (String key : scores.keySet()) {
System.out.println("Schlüssel: " + key + ", Wert: " + scores.get(key));
}
Über die Werte:
for (Integer value : scores.values()) {
System.out.println("Wert: " + value);
}
Über Schlüssel-Wert-Paare (die beste Methode):
for (Map.Entry<String, Integer> entry : scores.entrySet()) {
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key + " => " + value);
}
Wann verwendet man HashMap und wann – TreeMap?
HashMap ist die universelle Variante „per Default“. Wenn die Reihenfolge der Schlüssel egal ist und es vor allem auf Geschwindigkeit ankommt, nimmt man fast immer sie.
TreeMap ist sinnvoll, wenn Ordnung benötigt wird. Sie hält die Schlüssel automatisch sortiert und erlaubt es, den minimalen/maximalen Schlüssel schnell zu finden oder mit Bereichen zu arbeiten.
Fazit: In 90 % der Fälle nehmen wir HashMap. Wenn die Daten sofort „in Ordnung“ sein sollen, verwenden wir TreeMap.
6. Anwendungsbeispiele für Map
Beispiel 1: Telefonbuch
Map<String, String> phoneBook = new HashMap<>();
phoneBook.put("Kate", "+1-999-111-22-33");
phoneBook.put("Oliver", "+1-999-222-33-44");
phoneBook.put("Kate", "+1-999-555-66-77"); // Die alte Nummer von Kate wird durch die neue ersetzt
for (Map.Entry<String, String> entry : phoneBook.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
Ausgabe:
Oliver: +1-999-222-33-44
Kate: +1-999-555-66-77
Beispiel 2: Wortanzahl ermitteln
Angenommen, wir haben eine Liste von Wörtern und möchten wissen, wie oft jedes Wort vorkommt:
import java.util.*;
public class WordCount {
public static void main(String[] args) {
List<String> words = Arrays.asList("Apfel", "Banane", "Apfel", "Birne", "Banane", "Apfel");
Map<String, Integer> counts = new HashMap<>();
for (String word : words) {
int oldCount = counts.getOrDefault(word, 0); // wenn es den Schlüssel nicht gibt – 0
counts.put(word, oldCount + 1);
}
System.out.println(counts); // {Birne=1, Apfel=3, Banane=2}
}
}
7. Typische Fehler im Umgang mit Map
Fehler Nr. 1: Verwechslung von Schlüsseln und Werten. Anfänger versuchen oft, einen Wert per Index wie in einer Liste zu holen oder vergessen, dass Schlüssel eindeutig sein müssen. In der Map gibt es keine Indizes – nur Schlüssel.
Fehler Nr. 2: Verwendung von null-Schlüsseln und -Werten. In der HashMap ist ein null-Schlüssel erlaubt, in der TreeMap jedoch nicht (es gibt eine NullPointerException). Werte dürfen in beiden Implementierungen null sein, sind aber selten sinnvoll.
Fehler Nr. 3: Eine Ordnung in HashMap erwarten. HashMap garantiert keinerlei Ordnung. Wenn Sie Ordnung brauchen – verwenden Sie LinkedHashMap (erhält die Einfügereihenfolge) oder TreeMap (sortiert nach Schlüssel).
Fehler Nr. 4: Map während der Iteration verändern. Wenn Sie eine Map in einer Schleife durchlaufen und gleichzeitig Elemente hinzufügen/entfernen, kann eine ConcurrentModificationException auftreten. Für solche Aufgaben verwenden Sie einen Iterator mit der Methode remove() oder spezielle Collections.
Fehler Nr. 5: Schlüssel und Werte mit == statt equals vergleichen. Map verwendet die Methode equals zum Vergleichen von Schlüsseln (und Werten). Wenn Sie eigene Schlüsselklassen erstellen, überschreiben Sie unbedingt equals und hashCode.
GO TO FULL VERSION