当前位置: 首页 > news >正文

computeIfAbsent用法讲解

这是Java 中 Map 接口的 computeIfAbsent 方法。这是一个非常强大且实用的方法,可以极大地简化代码。

方法定义

首先,我们来看一下它的方法签名:

V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction)
  • key: 要与指定值关联的键。
  • mappingFunction: 一个函数式接口(通常是 Lambda 表达式或方法引用)。它接受 key 作为输入,并计算(Compute)出要返回的值。只有当 key 对应的映射不存在(Absent)或为 null 时,这个函数才会被调用。
  • 返回值: 返回与指定键关联的当前(现有的或新计算的)值;如果计算后的值仍为 null,则返回 null。

核心思想

computeIfAbsent 的行为可以概括为一句话::“如果不存在,则计算并放入”

检查 Map 中是否存在这个 key。如果不存在(或者对应的 value 是 null),则使用 mappingFunction 计算出一个新值,将这个 key-value 对放入 Map,并返回这个新值。如果 key 已经存在,则直接返回已存在的 value,mappingFunction 不会被调用。

它的内部逻辑类似于以下代码:

if (map.get(key) == null) {V newValue = mappingFunction.apply(key); // 根据key计算新值if (newValue != null) {map.put(key, newValue); // 如果新值不为空,则放入Mapreturn newValue;}
}
return map.get(key); // 如果key已存在或新值为空,返回现有的值(可能为null)

优点

在没有 computeIfAbsent 之前,我们通常这样写代码:

Map<String, List<String>> map = new HashMap<>();
String key = "fruits";// 传统写法
List<String> list = map.get(key);
if (list == null) {list = new ArrayList<>();list.add("Apple");map.put(key, list);
} else {list.add("Apple");
}// 使用 computeIfAbsent
List<String> list = map.computeIfAbsent(key, k -> new ArrayList<>());
list.add("Apple");

优点对比:

简洁性: 将检查、计算、放入和返回多个步骤合并成了一个原子操作,代码更加简洁。

原子性: 在多线程环境下,如果使用的是 ConcurrentHashMap,computeIfAbsent 的执行是线程安全的。整个“检查-计算-放入”过程是一个同步块,避免了竞态条件。

表达清晰: 代码的意图非常明确——“如果这个 key 没有值,就创建一个新的列表给我”。

使用场景

场景 1:分组归类(最常见)

这是一个非常经典的用法,用于构建一个“每个键对应一个集合”的 Map。

Map<String, List<Student>> studentsByClass = new HashMap<>();for (Student student : allStudents) {// 如果 className 不存在,就创建一个新 ArrayList 并放入Map// 然后返回这个 List(无论是新创建的还是已存在的),接着添加 studentstudentsByClass.computeIfAbsent(student.getClassName(), k -> new ArrayList<>()).add(student);
}

场景 2:缓存(Lazy Loading)

实现一个简单的缓存,只有在需要时才计算值。

Map<String, BigDecimal> priceCache = new HashMap<>();public BigDecimal getPrice(String productId) {return priceCache.computeIfAbsent(productId, this::calculatePriceFromDatabase);
}// 这是一个耗时的方法,只在第一次获取某个 productId 的价格时调用
private BigDecimal calculatePriceFromDatabase(String productId) {// ... 模拟复杂的数据库查询或网络请求return BigDecimal.TEN;
}

场景 3:初始化复杂对象

确保 Map 中的每个键都有一个初始化好的、非空的复杂对象。

Map<Integer, Config> configMap = new HashMap<>();// 获取 ID 为 123 的配置,如果没有则用默认配置初始化
Config config = configMap.computeIfAbsent(123, id -> new Config(...));
config.doSomething();

注意事项

mappingFunction 不应返回 null: 如果 mapping function 计算后返回 null,则不会创建任何映射,该方法也会返回 null。这通常不是你想要的,可能会导致后续的 NullPointerException。

ConcurrentHashMap 的线程安全性: 在 ConcurrentHashMap 中,computeIfAbsent 是线程安全的。整个计算过程是在锁内执行的,这意味着 mappingFunction 不应该是一个耗时很长的任务,否则会成为性能瓶颈。

递归调用: 严禁在 ConcurrentHashMap 的 computeIfAbsent 的 mappingFunction 中尝试再次修改这个 Map 本身(例如,再次调用 computeIfAbsent 或 put),这可能会导致死锁。


文章转载自:

http://aD91M3fL.Lfjmp.cn
http://d9bZD0x7.Lfjmp.cn
http://tCrUWFq4.Lfjmp.cn
http://odNMLuRC.Lfjmp.cn
http://IXtT2hc9.Lfjmp.cn
http://JPaNopEt.Lfjmp.cn
http://QhGMLIL9.Lfjmp.cn
http://R0NGMKCQ.Lfjmp.cn
http://cV0ZxKa0.Lfjmp.cn
http://VJZsdzGW.Lfjmp.cn
http://SdJ9VuB0.Lfjmp.cn
http://eZj4SUZi.Lfjmp.cn
http://DI0zQPGO.Lfjmp.cn
http://2W0JdjSS.Lfjmp.cn
http://3KDyQYf8.Lfjmp.cn
http://chZZwVfw.Lfjmp.cn
http://oKzFV1tq.Lfjmp.cn
http://oH2dFJ50.Lfjmp.cn
http://As8Wr8Il.Lfjmp.cn
http://Xix9SfzJ.Lfjmp.cn
http://8hVJGjEo.Lfjmp.cn
http://vJRusxPs.Lfjmp.cn
http://XHngSmxt.Lfjmp.cn
http://HSAnmLvI.Lfjmp.cn
http://1wGkpPEn.Lfjmp.cn
http://hvdM4QNL.Lfjmp.cn
http://DaeZF7u1.Lfjmp.cn
http://6wzKQPTY.Lfjmp.cn
http://PvIqSBiW.Lfjmp.cn
http://daUCHIZy.Lfjmp.cn
http://www.dtcms.com/a/388290.html

相关文章:

  • freertos代码结构
  • C++底层刨析章节一:STL概述与设计哲学:深入理解C++标准模板库的核心
  • 多态的原理与实现机制
  • [C++]异常
  • Windows PE 文件结构详解:从入口到执行的旅程
  • LLM 处理 PDF 表格的最佳方法:从解析到高效利用
  • 自动驾驶中的传感器技术50——Radar(11)
  • WALL-OSS--自变量机器人--2025.9.8--开源
  • GJOI 9.11/9.13 题解
  • 基于Spark的用户实时分析
  • 什么是 Conda 环境?
  • RK3506开发板QT Creator开发手册,交叉编译工具链与QT应用示例,入门必备
  • 颠覆3D生成,李飞飞团队新研究实现3D场景「无限探索」,AI构建世界模型能力跨越式进化
  • 3D 大模型生成虚拟世界
  • AI技术全景图:从大模型到3D生成,探索人工智能的无限可能
  • 一天认识一种模型方法--3D人体建模 SMPL
  • World Labs 的核心技术介绍:生成持久、可导航的 3D 世界
  • websocket如何推送最新日志
  • 使用Docker部署bewCloud轻量级Web云存储服务
  • web Service介绍
  • Web 架构中的共享存储:NFS 部署与用户压缩
  • RuoYi整合ZLM4j+WVP
  • @CrossOrigin的作用
  • Tree-shaking【前端优化】
  • Scikit-learn Python机器学习 - 分类算法 - 随机森林
  • 深入浅出Java中的Happens-Before原则!
  • centos7更换yum源
  • [特殊字符] 认识用户手册用户手册(也称用户指南、产品手册)是通过对产品功能的清
  • Codex 在 VS Code/Cursor 的插件基础配置
  • 前端Web案例-登录退出