entrySet()返回的是不可随机访问的Set视图,仅支持迭代遍历;正确方式是用增强for、Iterator或removeIf删除元素,修改value须调用entry.setValue(),禁止直接map.put()或在forEach中remove。

entrySet 返回的是 Set>,不是 List
很多人误以为 entrySet() 返回一个可按索引访问的集合,结果调用 get(0) 报错:「java.lang.UnsupportedOperationException」。它返回的是一个视图(view),底层由 HashMap/TreeMap 等维护,只支持迭代,不支持随机访问。
正确做法是用增强 for 或 iterator() 遍历:
for (Map.Entry<string integer> entry : map.entrySet()) {
String key = entry.getKey();
Integer value = entry.getValue();
// 执行转换逻辑,比如转成 DTO 或拼接字符串
}</string>
- 不要试图对
entrySet()调用stream().toList()再取元素——除非真需要随机访问,否则纯属浪费内存和 GC 压力 - 如果 map 很大且只需处理部分键值对,优先用
entrySet().iterator()+hasNext()/next()控制流程,避免一次性加载全部 Entry 对象
在 forEach 中修改 value 会同步反映到原 Map
Map.Entry 的 setValue() 是唯一允许在遍历时安全修改 value 的方式。直接改 map.put(key, newValue) 可能触发 ConcurrentModificationException(尤其用 HashMap 且未用 Iterator.remove())。
常见转换场景示例(把所有 value 加 10):
map.entrySet().forEach(entry -> entry.setValue(entry.getValue() + 10));
- 注意:key 不可变,
entry.setKey()不存在;改 key 必须用map.remove(oldKey); map.put(newKey, value) - 若转换逻辑涉及异步或耗时操作,请勿在
forEach里直接执行——它仍是单线程同步调用,容易阻塞主线程 -
LinkedHashMap的entrySet()保持插入顺序,TreeMap按 key 排序,这点会影响转换结果的可预测性
Stream 处理 entrySet 时注意装箱与中间操作开销
用 entrySet().stream() 做过滤、映射很常见,但容易忽略两层隐式成本:一是 Map.Entry 是对象,流式操作会生成大量临时对象;二是默认并行流(parallelStream())在小 map 上反而更慢。
典型转换逻辑(筛选 value > 100 的项,并转成新 Map):
Map<string string> result = map.entrySet().stream()
.filter(e -> e.getValue() != null && e.getValue() > 100)
.collect(Collectors.toMap(
Map.Entry::getKey,
e -> "processed_" + e.getValue()
));</string>
- 如果原 map 是
ConcurrentHashMap,别用parallelStream()——其分段锁机制与流的分区策略不协同,可能降低吞吐 - 避免在
map()中做复杂对象构造;如需构建 DTO,先用peek()记录日志或校验,再map(),否则异常堆栈难定位 -
Collectors.toMap()遇到重复 key 会抛IllegalStateException,生产代码中必须传入 merge 函数,例如(v1, v2) -> v1
遍历中删除 entry 必须用 Iterator.remove()
这是最常踩的坑:写 for (Entry e : map.entrySet()) { if (e.getValue() == 0) map.remove(e.getKey()); },运行时大概率抛 ConcurrentModificationException。
安全删除的唯一标准方式是:
Iterator<map.entry integer>> iter = map.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<string integer> entry = iter.next();
if (entry.getValue() == 0) {
iter.remove(); // 注意:这是 Iterator 的 remove,不是 map 的
}
}</string></map.entry>
-
iter.remove()是唯一被entrySet()视图允许的结构性修改操作 - 用
removeIf()更简洁:map.entrySet().removeIf(e -> e.getValue() == 0),本质也是基于迭代器 - 千万别在
forEach()或stream().forEach()里调map.remove(),JVM 不保证行为,不同 JDK 版本表现可能不一致
实际转换逻辑越复杂,越要警惕 Entry 对象的生命周期和 map 的并发模型。哪怕只是简单加个前缀,也要看清楚你操作的是视图还是副本、是否跨线程、有没有隐式装箱——这些细节不会报错,但会在高负载时突然暴露。










