Attic
CollectionsMaps

Iteration Patterns

Complete guide to all Map iteration techniques in Java, entrySet vs keySet performance, safe removal, and Streams

Iterating over a Map<K, V> in Java is fundamentally different from iterating over a List or Set because Map does not implement Iterable. Instead, iteration is performed through one of its three collection views (entrySet(), keySet(), values()), modern functional methods, or the Streams API.


The 6 Canonical Ways to Iterate a Map


1. entrySet() with Enhanced For Loop (Default Choice)

This is the most efficient and idiomatic way to iterate over a map when you need both the key and the value. It extracts both in a single pass without extra hash lookups.

EntrySetIteration.java
Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 95);
scores.put("Bob", 88);
scores.put("Charlie", 92);

for (Map.Entry<String, Integer> entry : scores.entrySet()) {
    String name = entry.getKey();
    Integer score = entry.getValue();
    System.out.println(name + " : " + score);
}

Why entrySet() is Optimal: In a hash map, each bucket already stores the key and value together in a single Node object. entrySet() visits each node directly, avoiding a second hash computation and bucket lookup.


2. keySet() with Enhanced For Loop (Keys Only)

Reach for keySet() only when your loop body only concerns keys, or when you plan to pass keys to external methods:

KeySetIteration.java
for (String name : scores.keySet()) {
    System.out.println("Student: " + name);
}

The keySet() + get(k) Anti-Pattern:

// ❌ SUB-OPTIMAL: Double lookup per row!
for (String key : map.keySet()) {
    Integer value = map.get(key); // Re-hashes key and traverses bucket again!
}

// ✅ OPTIMAL: Single pass!
for (Map.Entry<String, Integer> entry : map.entrySet()) {
    Integer value = entry.getValue();
}

3. values() with Enhanced For Loop (Values Only)

Use values() when you only need to process or aggregate values (e.g., calculating a sum or finding an average):

ValuesIteration.java
int totalScore = 0;
for (int score : scores.values()) {
    totalScore += score;
}
System.out.println("Average: " + (double) totalScore / scores.size());

4. forEach() with BiConsumer Lambda (Cleanest Syntax)

Introduced in Java 8, map.forEach() is the cleanest and most concise option for short loop bodies:

ForEachLambda.java
scores.forEach((name, score) -> {
    System.out.println(name + " earned " + score + " points");
});

5. Iterator via entrySet().iterator() (Safe In-Loop Removal)

Modifying a map directly inside an enhanced for loop throws a ConcurrentModificationException. To safely remove entries during traversal, use the iterator's own remove() method:

SafeIteratorRemove.java
Iterator<Map.Entry<String, Integer>> it = scores.entrySet().iterator();

while (it.hasNext()) {
    Map.Entry<String, Integer> entry = it.next();
    if (entry.getValue() < 90) {
        it.remove(); // Safely unlinks entry from the backing map
    }
}

6. Java Streams API (Filtering, Sorting, and Transforming)

The Streams API allows you to filter, transform, and sort map entries during iteration:

Filter and Collect to a New Map

StreamFilter.java
Map<String, Integer> highScorers = scores.entrySet().stream()
    .filter(e -> e.getValue() >= 90)
    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

Iterate Sorted by Key

SortByKey.java
scores.entrySet().stream()
    .sorted(Map.Entry.comparingByKey())
    .forEach(entry -> System.out.println(entry.getKey() + ": " + entry.getValue()));

Iterate Sorted by Value (Descending)

SortByValue.java
scores.entrySet().stream()
    .sorted(Map.Entry.<String, Integer>comparingByValue().reversed())
    .forEach(entry -> System.out.println(entry.getKey() + " -> " + entry.getValue()));

Performance & Selection Summary

Iteration StrategyTime OverheadMemory OverheadBest Used For
entrySet() loopO(n)NoneDefault choice when reading both keys and values
keySet() loopO(n)NoneWhen only keys are needed in the loop
values() loopO(n)NoneAggregating or inspecting values only
forEach() lambdaO(n)NoneClean, concise read-only traversal
iterator() with it.remove()O(n)MinimalRemoving entries conditionally during iteration
entrySet().removeIf()O(n)NoneCleanest in-place conditional filtering
entrySet().stream()O(n)Stream pipelineFiltering, complex sorting, and transforming

On this page