7 Ways to Iterate a Java HashMap and Their Performance Comparison

This article implements seven different HashMap traversal techniques in Java, benchmarks each with JMH, and shows that lambda‑based iteration and entrySet loops are the fastest, followed by Streams, while keySet‑based loops lag behind.

The Dominant Programmer
The Dominant Programmer
The Dominant Programmer
7 Ways to Iterate a Java HashMap and Their Performance Comparison

Scenario

The article uses JMH (Java Microbenchmark Harness) to measure and compare the performance of different ways to iterate a HashMap in Java.

HashMap traversal categories

From a high‑level perspective the traversal approaches fall into four groups:

Iterator

For‑Each

Lambda expression (JDK 1.8+)

Streams API (JDK 1.8+)

Each group contains concrete implementations, resulting in seven distinct methods:

Iterator over entrySet Iterator over keySet For‑Each over entrySet For‑Each over keySet Lambda forEach on the map

Streams API with a single‑threaded stream

Streams API with a parallel stream (excluded from the benchmark because its multithreaded nature guarantees the best raw throughput)

Concrete implementations

Iterator over entrySet:

public static void EntrySetForEach() {
    // create and populate HashMap
    Map<Integer,String> map = new HashMap<>();
    map.put(1,"公众号");
    map.put(2,"霸道的程序猿");
    map.put(3,"测试1");
    map.put(4,"测试2");
    map.put(5,"测试3");
    // iterate
    Iterator<Map.Entry<Integer,String>> iterator = map.entrySet().iterator();
    while (iterator.hasNext()) {
        Map.Entry<Integer,String> entry = iterator.next();
        System.out.println(entry.getKey());
        System.out.println(entry.getValue());
    }
}

Iterator over keySet:

public static void KeySetForEach() {
    Map<Integer,String> map = new HashMap<>();
    map.put(1,"公众号");
    map.put(2,"霸道的程序猿");
    map.put(3,"测试1");
    map.put(4,"测试2");
    map.put(5,"测试3");
    Iterator<Integer> iterator = map.keySet().iterator();
    while (iterator.hasNext()) {
        Integer key = iterator.next();
        System.out.println(key);
        System.out.println(map.get(key));
    }
}

For‑Each over entrySet:

public static void ForEachEntrySet() {
    Map<Integer,String> map = new HashMap<>();
    map.put(1,"公众号");
    map.put(2,"霸道的程序猿");
    map.put(3,"测试1");
    map.put(4,"测试2");
    map.put(5,"测试3");
    for (Map.Entry<Integer,String> entry : map.entrySet()) {
        System.out.println(entry.getKey());
        System.out.println(entry.getValue());
    }
}

For‑Each over keySet:

public static void ForEachKeySet() {
    Map<Integer,String> map = new HashMap<>();
    map.put(1,"公众号");
    map.put(2,"霸道的程序猿");
    map.put(3,"测试1");
    map.put(4,"测试2");
    map.put(5,"测试3");
    for (Integer key : map.keySet()) {
        System.out.println(key);
        System.out.println(map.get(key));
    }
}

Lambda forEach:

public static void LambdaForEach() {
    Map<Integer,String> map = new HashMap<>();
    map.put(1,"公众号");
    map.put(2,"霸道的程序猿");
    map.put(3,"测试1");
    map.put(4,"测试2");
    map.put(5,"测试3");
    map.forEach((key, value) -> {
        System.out.println(key);
        System.out.println(value);
    });
}

Streams API (single‑threaded):

public static void StreamSingle() {
    Map<Integer,String> map = new HashMap<>();
    map.put(1,"公众号");
    map.put(2,"霸道的程序猿");
    map.put(3,"测试1");
    map.put(4,"测试2");
    map.put(5,"测试3");
    map.entrySet().stream().forEach(entry -> {
        System.out.println(entry.getKey());
        System.out.println(entry.getValue());
    });
}

Streams API (parallel) – not included in the benchmark because its multithreaded nature guarantees the best raw throughput:

public static void StreamMul() {
    Map<Integer,String> map = new HashMap<>();
    map.put(1,"公众号");
    map.put(2,"霸道的程序猿");
    map.put(3,"测试1");
    map.put(4,"测试2");
    map.put(5,"测试3");
    map.entrySet().parallelStream().forEach(entry -> {
        System.out.println(entry.getKey());
        System.out.println(entry.getValue());
    });
}

Benchmark class

import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Warmup(iterations = 2, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Fork(1)
@State(Scope.Thread)
public class HashMapCycleTest {
    static Map<Integer,String> map = new HashMap<Integer,String>(){{
        for (int i = 0; i < 100; i++) {
            put(i, "value" + i);
        }
    }};

    public static void main(String[] args) throws RunnerException {
        Options options = new OptionsBuilder()
                .include(HashMapCycleTest.class.getSimpleName())
                .build();
        new Runner(options).run();
    }

    @Benchmark
    public void EntrySetForEach(){
        Iterator<Map.Entry<Integer,String>> iterator = map.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<Integer,String> entry = iterator.next();
            Integer key = entry.getKey();
            String value = entry.getValue();
        }
    }

    @Benchmark
    public void KeySetForEach(){
        Iterator<Integer> iterator = map.keySet().iterator();
        while (iterator.hasNext()) {
            Integer key = iterator.next();
            String value = map.get(key);
        }
    }

    @Benchmark
    public void ForEachEntrySet(){
        for (Map.Entry<Integer,String> entry : map.entrySet()) {
            Integer key = entry.getKey();
            String value = entry.getValue();
        }
    }

    @Benchmark
    public void ForEachKeySet(){
        for (Integer key : map.keySet()) {
            Integer k = key;
            String value = map.get(key);
        }
    }

    @Benchmark
    public void LambdaForEach(){
        map.forEach((key, value) -> {
            Integer k = key;
            String v = value;
        });
    }

    @Benchmark
    public void StreamSingle(){
        map.entrySet().stream().forEach(entry -> {
            Integer k = entry.getKey();
            String v = entry.getValue();
        });
    }
}

Test results

//Benchmark                         Mode  Cnt    Score     Error  Units
//HashMapCycleTest.EntrySetForEach  avgt    5  543.154 ±  36.365  ns/op
//HashMapCycleTest.ForEachEntrySet  avgt    5  533.511 ±  42.878  ns/op
//HashMapCycleTest.ForEachKeySet    avgt    5  805.146 ± 118.210  ns/op
//HashMapCycleTest.KeySetForEach    avgt    5  785.286 ±  68.913  ns/op
//HashMapCycleTest.LambdaForEach    avgt    5  429.048 ±  47.000  ns/op
//HashMapCycleTest.StreamSingle     avgt    5  501.687 ±  25.401  ns/op
Benchmark chart
Benchmark chart

Conclusion

The benchmark shows that the lambda‑based forEach and the two entrySet loops have almost identical performance and are the fastest among the tested methods. The single‑threaded Streams approach is slower but still better than the keySet‑based loops. Both keySet implementations rank last. Therefore, when performance is critical, prefer lambda or entrySet iteration for traversing a HashMap.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaPerformanceLambdaHashMapiterationJMH
The Dominant Programmer
Written by

The Dominant Programmer

Resources and tutorials for programmers' advanced learning journey. Advanced tracks in Java, Python, and C#. Blog: https://blog.csdn.net/badao_liumang_qizhi

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.