应优先使用 getordefault() 替代 if-else 判断 key 是否存在,因其语义清晰、仅一次哈希查找;频次统计可写为 map.put(word, map.getordefault(word, 0) + 1);注意类型一致、非空保障及并发安全时改用 merge() 或 computeifabsent()。

为什么不用 if-else 判断 key 是否存在
手动检查 Map.containsKey() 再取值或设默认值,容易写出重复、冗长的逻辑。比如统计单词频次时,常见写法是:
if (map.containsKey(word)) {
map.put(word, map.get(word) + 1);
} else {
map.put(word, 1);
}
这不仅多写三行,还对 word 做了两次哈希查找(containsKey 和 get 各一次),性能差且可读性弱。
getOrDefault() 怎么用在频次统计里
直接用 getOrDefault() 拿当前频次,加 1 后再 put(),一步到位:
map.put(word, map.getOrDefault(word, 0) + 1);
它内部只做一次哈希查找,语义清晰:「没出现过就当 0,否则取原值」。注意两点:
-
getOrDefault()第二个参数类型必须和 value 类型一致(如Integer,不能传int而期望自动装箱——虽然通常能隐式转换,但显式写0更安全) - 该方法不改变 map,只是读操作;真正修改靠后续的
put() - 如果 value 是可变对象(如
List),不能用getOrDefault(key, new ArrayList()),因为每次都会新建对象——那得用computeIfAbsent()
和 merge() 对比:什么场景该换用后者
Java 8+ 提供了更原子的 merge(),适合频次统计这种「读-改-写」模式:
map.merge(word, 1, Integer::sum);
它等价于:map.put(word, oldVal == null ? 1 : oldVal + 1),且线程安全(在单次调用内)。相比 getOrDefault() + put():
-
merge()是单次哈希操作,getOrDefault() + put()是两次(尽管 JVM 可能优化) -
merge()天然支持并发 map(如ConcurrentHashMap),而getOrDefault() + put()在并发下可能丢失更新 - 但
merge()的 lambda(如Integer::sum)不能为 null,且调试时堆栈更难追踪
实际写的时候容易漏掉的细节
最常踩的坑不是语法,而是类型和初始化:
- 别写成
map.getOrDefault(word, 0L)——返回Long,加 1 后再put()会导致 value 类型变成Long,后续getOrDefault(..., 0)可能因自动拆箱抛NullPointerException - 如果 map 是
HashMap<string atomicinteger></string>,别用getOrDefault,改用computeIfAbsent(word, k -> new AtomicInteger()).incrementAndGet(),避免重复创建对象 - 用
getOrDefault()前确认 map 非 null;它本身不抛NullPointerException,但后续操作可能因返回 null 崩溃(比如 value 类型是泛型V且未约束非空)
复杂点往往不在函数怎么调,而在你默认值的类型是否和 map 声明的 value 类型完全对齐,以及是否意识到这个操作本身不是原子的。










