Map是Java中一种重要的数据结构,用于存储键值对(Key-Value),其中键必须唯一,值可以重复,在实际开发中,遍历Map是常见的操作,比如获取所有键、值或键值对进行处理,本文将详细介绍Java中遍历Map的多种方式,包括各自的语法、适用场景、注意事项及性能对比,帮助开发者根据实际需求选择最合适的遍历方法。

使用keySet()结合for-each循环遍历
通过Map的keySet()方法可以获取所有键的集合,再通过for-each循环遍历键集合,并使用get(key)方法获取对应的值,这种方式语法简洁,适合只需要遍历键或需要频繁获取值的场景。
语法实现
Map<String, Integer> map = new HashMap<>();
map.put("Apple", 1);
map.put("Banana", 2);
map.put("Orange", 3);
for (String key : map.keySet()) {
Integer value = map.get(key);
System.out.println("Key: " + key + ", Value: " + value);
}
适用场景
- 只需要遍历Map中的键,不关心值;
- 需要在遍历过程中对每个键执行操作,同时需要获取对应的值。
注意事项
- 每次调用
map.get(key)都需要通过键查找值,底层依赖哈希计算(HashMap)或比较操作(TreeMap),如果Map较大或操作频繁,性能会低于直接遍历键值对; - 如果Map中的值为null,
get(key)会返回null,需注意空值处理,避免NullPointerException。
使用entrySet()结合for-each循环遍历(推荐方式)
entrySet()方法返回Map中所有键值对的集合(Set<Map.Entry<K,V>>),每个元素是一个Map.Entry对象,包含 getKey() 和 getValue() 方法,这种方式直接遍历键值对,无需二次查找,是遍历Map最高效的方式。
语法实现
for (Map.Entry<String, Integer> entry : map.entrySet()) {
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println("Key: " + key + ", Value: " + value);
}
适用场景
- 需要同时访问键和值,是绝大多数遍历场景的首选;
- 对性能要求较高的场景,entrySet()避免了keySet() + get()的重复查找开销。
注意事项
- entrySet()返回的Set是Map的视图,对Entry的修改(如setValue())会直接影响原Map;
- 遍历过程中直接修改Map的结构(如添加或删除键值对)会抛出ConcurrentModificationException,需结合迭代器安全删除。
使用迭代器(Iterator)遍历
迭代器是Java集合遍历的通用方式,支持在遍历过程中安全删除元素,避免并发修改异常,适用于需要动态修改Map结构的场景。
语法实现
遍历keySet()
Iterator<String> keyIterator = map.keySet().iterator();
while (keyIterator.hasNext()) {
String key = keyIterator.next();
Integer value = map.get(key);
if (value == null) {
keyIterator.remove(); // 安全删除键为null的键值对
}
}
遍历entrySet()(更高效)
Iterator<Map.Entry<String, Integer>> entryIterator = map.entrySet().iterator();
while (entryIterator.hasNext()) {
Map.Entry<String, Integer> entry = entryIterator.next();
if (entry.getValue() > 2) {
entryIterator.remove(); // 安全删除值大于2的键值对
}
}
适用场景
- 需要在遍历过程中删除或修改Map元素;
- 遍历非线程安全的Map(如HashMap)时,避免并发修改异常。
注意事项
- 必须使用iterator的remove()方法删除元素,不能直接调用Map的remove()方法,否则会抛出异常;
- 迭代器是“快速失败”(Fail-Fast)的,如果在遍历过程中检测到结构修改(除iterator.remove()外),会立即抛出ConcurrentModificationException。
使用Java 8 Stream API遍历
Java 8引入的Stream API提供了函数式编程风格的遍历方式,支持链式操作(如过滤、映射、聚合),适合处理复杂逻辑或并行计算场景。

语法实现
使用forEach()直接遍历
map.forEach((key, value) -> System.out.println("Key: " + key + ", Value: " + value));
使用Stream进行复杂操作
// 过滤出值大于1的键值对,并收集键到List
List<String> filteredKeys = map.entrySet()
.stream()
.filter(entry -> entry.getValue() > 1)
.map(Map.Entry::getKey)
.collect(Collectors.toList());
System.out.println("Filtered Keys: " + filteredKeys);
并行流遍历(适合大数据量)
map.entrySet().parallelStream().forEach(entry -> {
System.out.println(Thread.currentThread().getName() + " - Key: " + entry.getKey());
});
适用场景
- 需要对遍历结果进行进一步处理(过滤、排序、统计等);
- 函数式编程风格,代码更简洁;
- 大数据量场景下,并行流可提升处理效率。
注意事项
- forEach()是终端操作,执行后无法继续链式调用;
- 并行流(parallelStream)会使用多线程,需确保操作是线程安全的(如避免共享可变变量);
- Stream遍历不会修改原Map,若需修改需通过collect()或forEach中调用Map的修改方法。
遍历Map时的注意事项
-
并发修改异常
在遍历过程中直接使用Map的remove()、put()等方法修改结构,会抛出ConcurrentModificationException,安全方式:使用迭代器的remove(),或Java 8的removeIf()方法(如map.entrySet().removeIf(entry -> entry.getValue() == null))。 -
不同Map实现类的遍历特性
- HashMap:遍历顺序不确定(基于哈希值,可能因版本或JVM不同而变化);
- LinkedHashMap:按插入顺序或访问顺序遍历;
- TreeMap:按键的自然顺序或自定义 comparator 顺序遍历。
-
空值处理
HashMap的键和值均可为null,遍历时需通过Objects.equals()或Optional工具类避免空指针异常。 -
性能对比
综合性能:entrySet() > keySet() + get() > 迭代器(仅删除时),其中entrySet()只需一次哈希查找,而keySet() + get()需要两次(查找键+查找值),因此优先推荐entrySet()。
Java遍历Map的方式多样,开发者需根据场景选择:
- 简单遍历键或值:keySet() + for-each;
- 高效遍历键值对:entrySet() + for-each(通用首选);
- 遍历中删除元素:迭代器或removeIf();
- 复杂操作或函数式编程:Stream API。
掌握各种方式的原理和注意事项,能帮助开发者写出更高效、健壮的代码。
















