Java computeIfAbsent() 方法详解

文章目录
- 一、前言
- 二、方法定义
- 方法说明:
- 返回值:
- 三、基本使用示例
- 四、常见应用场景
- 五、与其他方法的区别
- 六、底层实现源码分析(以 `HashMap` 为例)
- 七、注意事项 ⚠️
一、前言
在 Java 编程中,我们经常需要在 Map 中保存一些“键对应的集合”或“键对应的统计信息”。
传统写法往往繁琐,比如:
Map<String, List<String>> map = new HashMap<>();if (!map.containsKey("Java")) {map.put("Java", new ArrayList<>());
}
map.get("Java").add("Tom");
是不是有点啰嗦?
从 Java 8 开始,我们可以用一行优雅的代码解决:
map.computeIfAbsent("Java", k -> new ArrayList<>()).add("Tom");
这就是今天的主角 —— computeIfAbsent()。
二、方法定义
computeIfAbsent() 是 Map 接口的一个默认方法,定义如下:
V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction)
方法说明:
| 参数 | 类型 | 含义 |
|---|---|---|
key | K | 要计算或查找的键 |
mappingFunction | Function<? super K, ? extends V> | 当键不存在时,用于生成新值的函数 |
返回值:
- 如果键已存在,返回原来的值;
- 如果键不存在,则使用
mappingFunction计算出一个新值,并放入Map; - 如果函数返回
null,则不会插入任何值。
三、基本使用示例
import java.util.*;public class ComputeIfAbsentDemo {public static void main(String[] args) {Map<String, List<String>> courseMap = new HashMap<>();// 当键不存在时,创建新列表courseMap.computeIfAbsent("Java", k -> new ArrayList<>()).add("Tom");courseMap.computeIfAbsent("Java", k -> new ArrayList<>()).add("Alice");courseMap.computeIfAbsent("Python", k -> new ArrayList<>()).add("Bob");System.out.println(courseMap);}
}
输出:
{Java=[Tom, Alice], Python=[Bob]}
✅
computeIfAbsent()自动处理了键的初始化逻辑,让代码更简洁。
四、常见应用场景
可参考如下题目熟练使用 computeIfAbsent()
49. 字母异位词分组 - 力扣(LeetCode)
五、与其他方法的区别
| 方法 | 说明 | 使用场景 |
|---|---|---|
putIfAbsent(key, value) | 如果 key 不存在,则放入指定的 value | 固定值插入 |
computeIfAbsent(key, func) | 如果 key 不存在,使用函数生成 value | 动态计算值 |
computeIfPresent(key, func) | 如果 key 存在,重新计算并更新 value | 修改已有值 |
compute(key, func) | 无论存在与否,都重新计算 | 全面控制更新逻辑 |
merge(key, value, remappingFunction) | 合并新旧值 | 统计与聚合 |
六、底层实现源码分析(以 HashMap 为例)
摘自 HashMap.java:
public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {Objects.requireNonNull(mappingFunction);Node<K,V> e;V v;if ((e = getNode(hash(key), key)) == null) {V newValue;if ((newValue = mappingFunction.apply(key)) != null) {putVal(hash(key), key, newValue, false, true);return newValue;}} else if ((v = e.value) == null) {V newValue;if ((newValue = mappingFunction.apply(key)) != null) {e.value = newValue;return newValue;}} else {return v;}return null;
}
简而言之:
- 如果 key 存在,直接返回 value;
- 如果不存在,则调用
mappingFunction.apply(key); - 若返回非空,则插入并返回;
- 否则不插入。
七、注意事项 ⚠️
- 不要让
mappingFunction产生副作用
map.computeIfAbsent("x", k -> {// ❌ 不要在这里修改 map 自身!map.put("y", "test");return "value";
});
否则可能引发 ConcurrentModificationException。
- 避免返回 null
如果函数返回 null,则不会插入任何值。
map.computeIfAbsent("key", k -> null);
// 不会添加任何条目
- 线程安全
- 普通
HashMap不是线程安全的; - 若需并发环境,请使用
ConcurrentHashMap; ConcurrentHashMap也支持computeIfAbsent(),且是线程安全版本。
- 普通
参考资料
Java HashMap computeIfAbsent() 方法 | 菜鸟教程
