Java8 Map的compute、computeIfPresent、computeIfAbsent区别以及使用场景

本文详细介绍了Java中Map接口的compute()、computeIfPresent()和computeIfAbsent()三个方法,通过测试用例展示了它们在修改、添加和删除数据时的不同行为。compute方法综合了computeIfPresent和computeIfAbsent的功能,而computeIfPresent仅在键值对存在时进行修改或删除,computeIfAbsent则在键不存在时添加数据。测试用例包括了各种可能的情况,并给出了相应的日志输出和结论。

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

介绍

以测试用例方式来展示Map的compute()、computeIfPresent()、computeIfAbsent()这三个方法的区别

结论

compute方法=computeIfPresent方法 + computeIfAbsent方法

一、compute(参数一、参数二)方法:

参数一:指定的key
参数二:接口函数(k,v)
结论:
(修改数据) 原始Map指定的key值存在,函数接口返回不会空,则用接口函数返回的结果替换key的value
(删除数据) 原始Map指定的key值存在,函数接口返回为空,删除key对应的数据
(添加数据) 原始Map指定的key值不存在,函数接口返回为不空,则添加一条数据到Map,key:指定的key value:函数返回的结果

二、computeIfPresent(参数一、参数二)

参数一:指定的key
参数二:接口函数(k,v)
结论:
(修改数据) 原始Map指定的key值存在,函数接口返回不会空,则用接口函数返回的结果替换key的value
(删除数据) 原始Map指定的key值存在,函数接口返回为空,删除key对应的数据

三、computeIfAbsent(参数一、参数二)

参数一:指定的key
参数二:接口函数(k)
结论:
(添加数据) 原始Map指定的key值不存在,函数接口返回为不空,则添加一条数据到Map,key:指定的key value:函数返回的结果

测试用例展示

完整代码:地址
为了代码简介,先写一个打印日志的方法:printLogAndReturnParam

/**
   * 打印前两个参数,返回第三参数
   *
   * @param k
   * @param v
   * @param result
   * @return
   */
  public static String printLogAndReturnParam(String k, String v, String result) {
    System.out.print("k-" + k + " ");
    System.out.println("v-" + v);
    return result;
  }

测试用例一、compute方法

测试代码
public void testMapCompute() {
    Map<String, String> map = new LinkedHashMap<>();
    System.out.println("测试场景:compute");
    map.put("k1", "v1");
    map.put("k2", "v2");
    map.put("k3", "v3");
    System.out.print("测试指定key存在,返回值一致:");
    map.compute("k1", (k, v) -> printLogAndReturnParam(k, v, "v1"));
    System.out.print("测试指定key存在,返回值不一致:");
    map.compute("k2", (k, v) -> printLogAndReturnParam(k, v, "VV2"));
    System.out.print("测试指定key存在,返回值为NULL:");
    map.compute("k3", (k, v) -> printLogAndReturnParam(k, v, null));
    System.out.print("测试指定key不存在,返回值NULL:");
    map.compute("k4", (k, v) -> printLogAndReturnParam(k, v, null));
    System.out.print("测试指定key不存在,返回值不为NULL:");
    map.compute("k5", (k, v) -> printLogAndReturnParam(k, v, "VV5"));
    System.out.print("输出结果:" + map);
    System.out.println("结论如下:");
    System.out.println("测试指定key存在,返回值一致:value保持不变");
    System.out.println("测试指定key存在,返回值不一致:value使用返回值");
    System.out.println("测试指定key存在,返回值为NULL:删除该条数据");
    System.out.println("测试指定key不存在,返回值NULL:不添加不删除");
    System.out.println("测试指定key不存在,返回值不为NULL:添加数据,key:指定的key,value:返回值");
  }
日志输出

测试场景:compute
测试指定key存在,返回值一致:k-k1 v-v1
测试指定key存在,返回值不一致:k-k2 v-v2
测试指定key存在,返回值为NULL:k-k3 v-v3
测试指定key不存在,返回值NULL:k-k4 v-null
测试指定key不存在,返回值不为NULL:k-k5 v-null
输出结果:{k1=v1, k2=VV2, k5=VV5}结论如下:
测试指定key存在,返回值一致:value保持不变
测试指定key存在,返回值不一致:value使用返回值
测试指定key存在,返回值为NULL:删除该条数据
测试指定key不存在,返回值NULL:不添加不删除
测试指定key不存在,返回值不为NULL:添加数据,key:指定的key,value:返回值

测试用例二、computeIfPresent方法

测试代码
public void testMapComputeIfPresent() {
    Map<String, String> map = new LinkedHashMap<>();
    System.out.println("测试场景:computeIfPresent");
    map.put("k1", "v1");
    map.put("k2", "v2");
    map.put("k3", "v3");
    System.out.print("测试指定key存在,返回值一致:");
    map.computeIfPresent("k1", (k, v) -> printLogAndReturnParam(k, v, "v1"));
    System.out.print("测试指定key存在,返回值不一致:");
    map.computeIfPresent("k2", (k, v) -> printLogAndReturnParam(k, v, "VV2"));
    System.out.print("测试指定key存在,返回值为NULL:");
    map.computeIfPresent("k3", (k, v) -> printLogAndReturnParam(k, v, null));
    System.out.println("测试指定key不存在,返回值NULL:");
    map.computeIfPresent("k4", (k, v) -> printLogAndReturnParam(k, v, null));
    System.out.println("测试指定key不存在,返回值不为NULL:");
    map.computeIfPresent("k5", (k, v) -> printLogAndReturnParam(k, v, "VV5"));
    System.out.print("输出结果:" + map);
    System.out.println("结论如下:");
    System.out.println("测试指定key存在,返回值一致:value保持不变");
    System.out.println("测试指定key存在,返回值不一致:value使用返回值");
    System.out.println("测试指定key存在,返回值为NULL:删除该条数据");
    System.out.println("测试指定key不存在,返回值NULL:不添加不删除");
    System.out.println("测试指定key不存在,返回值不为NULL:不添加不删除");
  }
日志输出

测试场景:computeIfPresent
测试指定key存在,返回值一致:k-k1 v-v1
测试指定key存在,返回值不一致:k-k2 v-v2
测试指定key存在,返回值为NULL:k-k3 v-v3
测试指定key不存在,返回值NULL:
测试指定key不存在,返回值不为NULL:
输出结果:{k1=v1, k2=VV2}结论如下:
测试指定key存在,返回值一致:value保持不变
测试指定key存在,返回值不一致:value使用返回值
测试指定key存在,返回值为NULL:删除该条数据
测试指定key不存在,返回值NULL:不添加不删除
测试指定key不存在,返回值不为NULL:不添加不删除

测试用例三、computeIfAbsent方法

测试代码
public void testMapComputeIfAbsent() {
    Map<String, String> map = new LinkedHashMap<>();
    System.out.println("测试场景:computeIfAbsent");
    map.put("k1", "v1");
    map.put("k2", "v2");
    map.put("k3", "v3");
    System.out.println("测试指定key1存在,返回值一致");
    map.computeIfAbsent("k1", k -> "v1");
    System.out.println("测试指定key2存在,返回值不一致");
    map.computeIfAbsent("k2", k -> "VV2");
    System.out.println("测试指定key3存在,返回值为NULL");
    map.computeIfAbsent("k3", k -> null);
    System.out.println("测试指定key4不存在,返回值NULL");
    map.computeIfAbsent("k4", k -> null);
    System.out.println("测试指定key5不存在,返回值不为NULL");
    map.computeIfAbsent("k5", k -> "VV5");
    System.out.print("输出结果:" + map);
    System.out.println("结论如下:");
    System.out.println("测试指定key存在,返回值一致:不添加不删除");
    System.out.println("测试指定key存在,返回值不一致:不添加不删除");
    System.out.println("测试指定key存在,返回值为NULL:不添加不删除");
    System.out.println("测试指定key不存在,返回值NULL:不添加不删除");
    System.out.println("测试指定key不存在,返回值不为NULL:添加数据,key:指定的key,value:指定的value");
  }
日志输出

测试场景:computeIfAbsent
测试指定key1存在,返回值一致
测试指定key2存在,返回值不一致
测试指定key3存在,返回值为NULL
测试指定key4不存在,返回值NULL
测试指定key5不存在,返回值不为NULL
输出结果:{k1=v1, k2=v2, k3=v3, k5=VV5}结论如下:
测试指定key存在,返回值一致:不添加不删除
测试指定key存在,返回值不一致:不添加不删除
测试指定key存在,返回值为NULL:不添加不删除
测试指定key不存在,返回值NULL:不添加不删除
测试指定key不存在,返回值不为NULL:添加数据,key:指定的key,value:指定的value

<think>好的,我现在需要回答用户关于JavaMapcomputeIfPresentcomputeIfAbsent方法的区别及用法的问题。首先,我应该回忆一下这两个方法的具体定义和它们在Java文档中的描述。我记得这两个方法都是Java 8引入的,属于Map接口的默认方法,用于更灵活地处理键值对的更新和计算。 computeIfPresent的作用是当指定的键存在于Map中时,执行给定的函数来重新计算该键的值。如果键存在,并且计算结果不为null,则更新键对应的值;如果计算结果为null,则会删除该键。如果键不存在,这个方法不会做任何事情,直接返回null。 而computeIfAbsent则是当指定的键不存在于Map中时,执行给定的函数来计算新值,并将键值对插入到Map中。如果键已经存在,这个方法不会执行任何操作,直接返回当前存在的值。此外,如果计算出的值为null,这个方法也不会插入新的条目,因为Map不允许null值。 接下来,我需要考虑用户可能的理解难点。比如,这两个方法在处理null值时的行为差异,以及它们与传统的put或replace方法的区别。用户可能想知道在什么情况下使用哪个方法更合适,以及如何避免常见的错误,比如在computeIfAbsent中执行有副作用的操作,或者处理可能返回null的函数导致的问题。 然后,我需要构思一些具体的例子来说明这两个方法的使用场景。比如,使用computeIfPresent来累加已存在的键的值,或者使用computeIfAbsent来初始化一个键的值,特别是当初始化过程比较耗时时,可以避免重复计算。例如,构建一个缓存或者统计频率的Map。 另外,要注意在例子中展示当函数返回null时,computeIfPresent会删除现有的键,而computeIfAbsent则不会插入新键。这有助于用户理解这两个方法对Map结构的影响。 还需要提到性能方面的考虑,比如computeIfAbsent在计算函数返回null时不会修改Map,这有助于避免不必要的计算和可能的ConcurrentModificationException。同时,在多线程环境下,虽然ConcurrentHashMapcompute方法提供了原子性操作,但用户仍需注意函数的副作用和线程安全问题。 最后,总结两者的区别,强调computeIfPresent处理现有键的更新,computeIfAbsent处理新键的插入,并且两者都依赖于函数的结果来决定是否更新或插入。同时,提醒用户注意null值的处理和函数的副作用,确保代码的正确性和高效性。</think>### Java MapcomputeIfPresentcomputeIfAbsent区别及用法 #### 1. **核心区别** | **方法** | **触发条件** | **行为** | **返回值** | **是否修改Map** | |---------------------|--------------------|-------------------------------------------------------------------------|-------------------------------|-------------------------| | `computeIfPresent` | 键存在且值非`null` | 根据函数计算结果更新值,若结果为`null`则删除键值对 | 更新后的值(或`null`) | 可能删除或更新 | | `computeIfAbsent` | 键不存在或值为`null` | 根据函数计算新值并插入键值对(若结果非`null`) | 原值(若存在)或新插入的值 | 可能新增键值对 | #### 2. **使用场景与示例** ##### **场景1:统计词频(累加操作)** ```java Map<String, Integer> wordCount = new HashMap<>(); // computeIfPresent示例 wordCount.put("apple", 1); wordCount.computeIfPresent("apple", (k, v) -> v + 1); // apple → 2 // computeIfAbsent示例 wordCount.computeIfAbsent("banana", k -> 0); // banana → 0(初始化默认值) ``` ##### **场景2:缓存计算结果** ```java Map<Integer, BigInteger> factorialCache = new HashMap<>(); // 仅当键不存在时计算阶乘(避免重复计算) factorialCache.computeIfAbsent(5, n -> { BigInteger result = BigInteger.ONE; for (int i = 2; i <= n; i++) { result = result.multiply(BigInteger.valueOf(i)); } return result; }); // 5 → 120 ``` #### 3. **关键注意事项** - **`null`值处理**: - `computeIfPresent`的函数返回`null`会删除键,例如: ```java map.computeIfPresent("key", (k, v) -> null); // 删除"key" ``` - `computeIfAbsent`的函数返回`null`不会插入新键值对[^1] - **原子性**: 在`ConcurrentHashMap`中,这两个方法保证原子性操作,但函数应避免外部依赖[^2] - **副作用**: 避免在函数中修改外部状态(如IO操作),可能导致不可预测行为 #### 4. **与类似方法的对比** | **操作** | 与`put`的区别 | 与`merge`的关联 | |------------------|----------------------------------------|----------------------------------------| | `computeIfAbsent` | 仅在键缺失时插入,且函数返回值决定操作 | 可视为`merge`的特例(仅处理缺失键) | | `computeIfPresent`| 仅更新现有键,支持删除操作 | 类似`merge`但限定键存在时的行为 | ####
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值