map.entryset()是链式过滤的起点,必须通过它获取stream才能安全进行键值联合操作,跳过此步会导致数据丢失、并发异常或运行时崩溃。

Map.entrySet() 是链式过滤的起点,不是 for 循环替代品
Java 里 Map 本身不支持直接流式操作,必须先转成 entrySet() 才能用 stream()。跳过这步、试图对 keySet() 或 values() 做“键值联合过滤”会丢数据——比如你想筛出“value > 100 且 key 以 "user_" 开头”的项,只遍历 key 或只遍历 value 都没法同时拿到两者。
-
map.entrySet().stream()返回的是Stream<map.entry>></map.entry>,这才是带键又带值的完整单元 - 别用
map.keySet().stream().filter(...).map(map::get):可能触发多次get(),且 null 值或并发修改时行为不可靠 - 如果 Map 是
ConcurrentHashMap,entrySet()流是弱一致性快照,不会抛ConcurrentModificationException,但也不保证实时性
filter() 里必须解构 Map.Entry,不能直接写 key/value 字段名
Stream 的 filter() 接收的是 Map.Entry 对象,不是解包后的 key 和 value。常见错误是写成 filter(entry -> key.startsWith("user_")) —— 编译不过,因为 key 不在作用域里。
- 正确写法是显式调用
entry.getKey()和entry.getValue() - 为减少重复调用,可提前解构:
filter(entry -> { String k = entry.getKey(); Integer v = entry.getValue(); return k.startsWith("user_") && v != null && v > 100; }) - 如果 value 类型是泛型(如
V extends Number),注意getValue()返回的是Object,需安全转型,否则可能抛ClassCastException
collect(Collectors.toMap()) 的 merge 冲突处理容易漏掉
链式过滤后想转回 Map,用 collect(Collectors.toMap()) 最常见。但它默认不允许重复 key,而原始 Map 的 key 本来就不重复,所以看似安全——但如果你在 filter 后又做了 map() 改 key(比如统一加前缀),就可能引入冲突。
- 不指定 merge 函数时,重复 key 会直接抛
IllegalStateException: Duplicate key xxx - 必须显式传第三个参数,例如
(v1, v2) -> v1表示保留第一个值 - 如果原始 Map 是
LinkedHashMap,用toMap()默认构造的HashMap会丢失插入顺序;要保持顺序得用Collectors.toMap(k, v, (a,b)->a, LinkedHashMap::new)
性能敏感场景下,避免无谓的 Stream 包装和对象创建
对小 Map(比如 size
- 如果只是简单条件(如
value != null),用removeIf()原地过滤更轻量:map.entrySet().removeIf(e -> e.getValue() == null) - Stream 中的
map()操作每项都新建一个Map.Entry(除非你用AbstractMap.SimpleImmutableEntry手动构造),而 for-each 可复用引用 - Android 或低内存环境慎用,
Stream在旧版 ART 上 GC 压力更大










