W3docs

Wie man eine HashMap in Java iteriert

Java HashMap-Einträge mit entrySet, keySet, values, forEach und Streams iterieren – alle gängigen Methoden erklärt.

Eine HashMap speichert Schlüssel-Wert-Paare, und früher oder später muss man sie durchlaufen – um einen Bericht auszugeben, Werte zu summieren oder Einträge zu filtern. Java bietet mehrere idiomatische Möglichkeiten dafür, jede für einen leicht anderen Zweck geeignet: Braucht man Schlüssel, Werte oder beides? Dieses Kapitel behandelt die gebräuchlichen Ansätze – entrySet(), keySet(), values(), forEach und einen entfernenden Iterator – und erklärt, wann man welchen verwenden sollte.

Diese Techniken gelten für jede Map-Implementierung, einschließlich LinkedHashMap und TreeMap, da sie alle dieselbe Iterations-API teilen.

Einträge mit entrySet() durchlaufen

Wenn man sowohl den Schlüssel als auch den Wert benötigt, ist entrySet() die effizienteste Wahl. Es gibt eine Ansicht von Map.Entry-Objekten zurück, und ein einziger Durchlauf liefert jedes Paar ohne eine zweite Suche:

Map<String, Integer> stock = new HashMap<>();
for (Map.Entry<String, Integer> e : stock.entrySet()) {
    System.out.println(e.getKey() + " -> " + e.getValue());
}

Dies ist der empfohlene Standard. keySet() zu verwenden und dann innerhalb der Schleife map.get(key) aufzurufen, führt pro Element zu einer redundanten Hash-Suche; entrySet() vermeidet das vollständig.

Nur Schlüssel oder Werte iterieren

Wenn man nur eine Seite jedes Paares benötigt, fordert man genau diese Ansicht an. keySet() gibt die Schlüssel zurück, values() gibt die Werte zurück:

for (String key : stock.keySet()) {
    System.out.println("key: " + key);
}
for (int qty : stock.values()) {
    System.out.println("qty: " + qty);
}

Beide Ansichten werden durch die Map unterstützt und spiegeln deren aktuellen Inhalt wider, ohne ihn zu kopieren. keySet() verwendet man, wenn die Werte wirklich nicht benötigt werden, und values(), wenn die Schlüssel irrelevant sind.

Die forEach-Methode

Seit Java 8 hat Map eine forEach-Methode, die einen BiConsumer entgegennimmt und Schlüssel und Wert als Lambda-Parameter bereitstellt. Sie ist prägnant und gut lesbar für einfache Seiteneffekte:

stock.forEach((key, value) -> System.out.println(key + "=" + value));

Innerhalb eines Lambdas gibt es kein break oder continue, daher ist für ein frühzeitiges Beenden oder komplexe Kontrollflüsse eine klassische for-Schleife nach wie vor klarer.

Sicheres Entfernen mit einem Iterator

Das strukturelle Ändern einer Map, während eine for-each-Schleife darüber läuft, wirft eine ConcurrentModificationException. Um Einträge während des Durchlaufs zu entfernen, verwendet man einen expliziten Iterator und ruft dessen remove() auf:

Iterator<Map.Entry<String, Integer>> it = stock.entrySet().iterator();
while (it.hasNext()) {
    if (it.next().getValue() < 10) {
        it.remove();
    }
}

Eine moderne Alternative ist stock.entrySet().removeIf(e -> e.getValue() < 10), die denselben Filter in einer Zeile ausdrückt.

AnsatzLiefertAm besten geeignet für
entrySet()Schlüssel + WertStandard; beide lesen
keySet()Nur SchlüsselArbeit mit Schlüsseln
values()Nur WerteSummen, Wertdurchläufe
forEachSchlüssel + Wert (Lambda)Prägnante Seiteneffekte
IteratorSchlüssel + WertEntfernen während des Durchlaufs
java— editable, runs on the server

Was man aus dem Programmlauf mitnehmen kann:

  • Die entrySet()-Schleife liest jeden Schlüssel und Wert in einem einzigen Durchlauf und akkumuliert Total stock: 39, indem sie 12 + 7 + 20 summiert.
  • keySet() gibt nur die Schlüssel aus (apple, banana, cherry), während values() nur die Zahlen ausgibt, was zeigt, dass jede Ansicht eine Seite des Paares offenlegt.
  • Das forEach-Lambda erzeugt dieselben Schlüssel=Wert-Zeilen wie die manuelle Schleife und bestätigt, dass es ein prägnantes Äquivalent für einfache Iterationen ist.
  • Es wurde eine LinkedHashMap verwendet, damit die Ausgabe die Einfügereihenfolge beibehält – eine einfache HashMap gibt keine Reihenfolgegarantie, sodass die Zeilen in beliebiger Reihenfolge erscheinen könnten.
  • Der Iterator.remove()-Aufruf entfernt banana (Wert 7, unter 10) und hinterlässt {apple=12, cherry=20}, was eine sichere Löschung während der Schleife ohne ConcurrentModificationException demonstriert.

Übungen

Übung
Welche Methode ermöglicht es, sowohl den Schlüssel als auch den Wert in einer einzigen Iteration ohne eine zweite Suche abzurufen?
Welche Methode ermöglicht es, sowohl den Schlüssel als auch den Wert in einer einzigen Iteration ohne eine zweite Suche abzurufen?
Was this page helpful?