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.
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/opConclusion
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.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
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
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
