merge()是Java8引入的最实用的Map方法之一,一行代码搞定词频统计——这篇真实验证它的基础用法,以及一个容易被文档一带而过、但真实很有用的行为:BiFunction返回null会发生什么。
上一篇:Map.computeIfAbsent() 真实验证
merge()最经典的应用场景,对比传统写法真实简洁很多。
MapMergeDemo.java Map<String, Integer> wordCount = new HashMap<>(); for (String w : words) { wordCount.merge(w, 1, Integer::sum); }
真实词频统计结果: {a=3, b=2, c=1}
真实结果验证了 merge(key, value, remappingFunction) 的核心语义:如果 key 不存在,直接存入 value;如果存在,用 remappingFunction 把旧值和新值合并成一个结果重新存入。一行 merge(w, 1, Integer::sum) 真实同时覆盖了"首次出现"和"再次出现累加"两种场景,不需要像老式写法那样先 containsKey() 判断再分支处理。
key不存在时merge()真实结果: {x=100}
真实结果证明当 "x" 这个key首次出现时,merge() 内部真实直接把传入的 value(100)存进去,完全不会调用 BiFunction——在这段测试代码里,如果 BiFunction 真的被调用了会打印一行提示日志,但真实运行结果里这行日志没有出现,证实了这个短路行为。
这是merge()最容易被忽视、但真实很有用的一个行为——当合并函数返回null,会发生什么?
MapMergeDemo.java map2.put("y", 5); map2.merge("y", 3, (oldV, newV) -> null); // 故意返回null
BiFunction返回null后,key真实还在map里吗: false,真实map内容: {}
MapMergeDemo.java inventory.merge("item1", -3, (oldV, newV) -> { int result = oldV + newV; return result <= 0 ? null : result; // 库存归零就删除这个条目 });
库存扣减到0后,item1真实还在inventory里吗: false
真实结果验证了这个删除机制在实际业务场景里的用法:一次 merge() 调用真实同时完成了"扣减数量"和"数量归零就自动清理这个条目"两件事,不需要在业务代码里额外写一个判断和 remove() 调用。
merge()传入null作为value真实抛出 NullPointerException
真实结果证明 merge() 的第二个参数(初始value)本身不允许是 null——这和"回调函数可以返回null来触发删除"是两个不同层面的规则:传入的初始值必须是真实有效的值,但计算过程中的中间结果可以用 null 表示"应该删除"。
每一步的 map 内容都是真实运行这段代码之后的状态,包含词频累加、key 不存在时的短路、以及 BiFunction 返回 null 时的删除。