Map中的compute、computeIfAbsent和computeIfPresent的使用和区别

本文详细介绍了Java中Map接口的computeIfAbsent、computeIfPresent和compute方法的使用,通过实例展示了它们如何根据键查询并更新或添加Map中的数据。这三个方法在Map操作中提供了便捷的条件赋值和更新功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Map中的compute、computeIfAbsent和computeIfPresent的使用和区别

先准备一个简单的map数据吧

        Map<Long, String> testMap = new HashMap<>();
        testMap.put(1L, "张三");
        testMap.put(2L, "李四");
        testMap.put(3L, "王五");

computeIfAbsent

简单来说这个方法就是根据第一个参数key,去查询map,只有当返回值为null即Map中查询不到对应的数据时,向Map中添加一条数据

        //测试,没有新增
        testMap.computeIfAbsent(4L, aLong -> "computeIfAbsent");
        //有返回值,不做任何操作
        testMap.computeIfAbsent(3L, aLong -> "computeIfAbsent2");

操作之前的截图
在这里插入图片描述
没有的新增
在这里插入图片描述
有的不做操作
在这里插入图片描述

computeIfPresent

简单来说这个方法就是根据第一个参数key,去查询map,如果查询到了就更新对应的值,如果查询不到,不做任何操作

        //Map中有就更新,没有不做操作
        testMap.computeIfPresent(2L, (aLong, s) -> "computeIfPresent");
        //Map中没有不做操作
        testMap.computeIfPresent(5L, (aLong, s) -> "computeIfPresent2");

有就更新
在这里插入图片描述

没有不做操作
在这里插入图片描述

compute

简单来说这个方法就是根据第一个参数key,去查询map,无论是否查询到,都会执行第二个方法体,没有就新增,有就更新值

        testMap.compute(1L, (aLong, s) -> "compute");
        testMap.compute(6L, (aLong, s) -> "compute2");

有就更新
在这里插入图片描述

没有就新增
在这里插入图片描述

完整代码

Map<Long, String> testMap = new HashMap<>();
testMap.put(1L, "张三");
testMap.put(2L, "李四");
testMap.put(3L, "王五");
//测试,没有新增
testMap.computeIfAbsent(4L, aLong -> "computeIfAbsent");
//有返回值,不做任何操作
testMap.computeIfAbsent(3L, aLong -> "computeIfAbsent2");
//Map中有就更新,没有不做操作
testMap.computeIfPresent(2L, (aLong, s) -> "computeIfPresent");
//Map中没有不做操作
testMap.computeIfPresent(5L, (aLong, s) -> "computeIfPresent2");
//有就更新
testMap.compute(1L, (aLong, s) -> "compute");
//没有就新增
testMap.compute(6L, (aLong, s) -> "compute2");
<think>好的,我需要回答用户关于Java MapcomputeIfPresentcomputeIfAbsent方法的区别及用法的问题。用户之前已经询问过computeIfAbsent,现在想了解两者的对比。我需要结合之前的回答用户提供的引用内容,特别是引用[3]中提到的Java Map设置值的方法。 首先,回顾一下computeIfAbsent的要点:当键不存在时,使用提供的函数计算值并插入Map。而computeIfPresent则是在键存在时对值进行操作。需要明确两者的触发条件返回值的不同。 接下来,需要区分两者的方法签名参数类型。computeIfAbsent接收一个Function,而computeIfPresent接收一个BiFunction,因为后者需要现有的键值来生成新值。 然后,结合用户提供的引用[3],其中讨论了高效增加Map值的方法,可能涉及到computeIfPresent的应用场景,比如更新现有值。例如,当需要递增某个键对应的数值时,可以使用computeIfPresent来避免空值检查。 还需要考虑线程安全的问题,引用[1]中的比较器可能不直接相关,但用户之前的问题提到过ConcurrentHashMap中的原子操作,需要指出在并发环境下使用这些方法时的注意事项。 另外,引用[4]关于Java的静态类型可能提醒在函数中使用正确的类型,避免类型错误。例如,computeIfPresent的BiFunction必须返回正确类型的值,否则会导致编译错误。 现在需要组织内容,分点解释两者的区别使用示例代码说明,并给出典型应用场景。同时,确保引用之前提到的注意事项,如线程安全空值处理。 可能的结构: 1. 方法定义对比 - computeIfAbsent: 键不存在时计算 - computeIfPresent: 键存在时计算 2. 参数类型差异 - Function vs BiFunction 3. 返回值处理 - computeIfAbsent返回新值或旧值 - computeIfPresent返回新值或null 4. 使用场景举例 - computeIfAbsent用于缓存、分组初始化 - computeIfPresent用于更新、累加操作 5. 注意事项 - 函数副作用 - 并发环境下的原子性 最后,生成相关问题,引导用户进一步学习,如与putIfAbsent的区别,或者如何处理并发情况。</think>### Java Map computeIfPresentcomputeIfAbsent 方法对比详解 --- #### 一、核心逻辑对比 | **方法** | **触发条件** | **参数类型** | **返回值规则** | |----------------------|-----------------------|--------------------|--------------------------------------------------------------------------------| | `computeIfAbsent` | 键 **不存在** 时触发 | `Function<K, V>` | 若键不存在:执行函数生成值并插入,返回新值;若键存在:直接返回当前值 | | `computeIfPresent` | 键 **存在** 时触发 | `BiFunction<K, V, V>` | 若键存在:根据旧值新函数计算结果更新,返回新值;若键不存在:直接返回 `null` | --- #### 二、方法定义与使用示例 ##### 1. `computeIfAbsent` ```java // 方法签名 V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) // 示例:缓存文件内容 Map<String, String> fileCache = new HashMap<>(); String content = fileCache.computeIfAbsent("config.txt", k -> readFile(k)); // 仅当键不存在时读取文件 ``` ##### 2. `computeIfPresent` ```java // 方法签名 V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) // 示例:更新用户积分 Map<String, Integer> userPoints = new HashMap<>(); userPoints.put("Alice", 100); userPoints.computeIfPresent("Alice", (k, v) -> v + 50); // Alice 积分变为 150 userPoints.computeIfPresent("Bob", (k, v) -> v + 10); // 无操作,返回 null ``` --- #### 三、典型使用场景差异 | **场景** | computeIfAbsent | computeIfPresent | |-----------------------|------------------------------------------|-------------------------------------------| | **延迟初始化** | 首次访问时初始化值(如缓存、连接池)[^3] | 不适用 | | **数据聚合** | 初始化集合容器(如分组统计) | 更新现有集合(如追加元素) | | **条件更新** | 无 | 基于旧值计算新值(如计数器递增、状态转换) | | **空值处理** | 自动处理键不存在的情况 | 自动跳过键不存在的操作 | --- #### 四、关键差异总结 1. **触发条件相反** - `computeIfAbsent` 仅在键不存在时执行 - `computeIfPresent` 仅在键存在时执行 2. **参数类型不同** - `computeIfAbsent` 使用 `Function`(仅接收键生成值) - `computeIfPresent` 使用 `BiFunction`(接收键旧值生成新值)[^3] 3. **返回值规则** - `computeIfAbsent` 保证返回非空值(除非函数返回 `null`) - `computeIfPresent` 可能返回 `null`(当键不存在或函数返回 `null` 时) 4. **并发行为** - 在 `ConcurrentHashMap` 中,两者均为原子操作,但需确保函数无副作用[^1] --- #### 五、综合应用示例 **场景:统计单词频率(同时处理存在/不存在的键)** ```java Map<String, Integer> wordCounts = new HashMap<>(); List<String> words = Arrays.asList("apple", "banana", "apple", "orange", "banana"); words.forEach(word -> { // 首次出现时初始化为1,后续出现时递增 wordCounts.computeIfAbsent(word, k -> 1); wordCounts.computeIfPresent(word, (k, v) -> v + 1); }); // 输出:apple=2, banana=2, orange=1 System.out.println(wordCounts); ``` --- #### 六、注意事项 1. **空值处理** - `computeIfAbsent` 函数返回 `null` 时不插入键值对 - `computeIfPresent` 函数返回 `null` 时会删除现有键值对 2. **线程安全** - 在并发环境下推荐使用 `ConcurrentHashMap`,但需避免在函数中操作外部状态[^2] 3. **性能优化** - 对于高频更新操作,优先使用 `computeIfPresent` 而非 `get` + `put` 组合(减少哈希查找次数)[^3] --- ### 相关问题 1. 如何用 `compute` 方法统一处理键存在/不存在的情况? 2. `computeIfPresent` 与 `replace` 方法有何异同? 3. 为什么在并发环境下需要特别注意 `computeIfPresent` 的函数副作用?
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值