Map中compute()、computeIfPresent()、computeIfAbsent()、merge()的使用以及原理

1. 总结

  1. compute():无论key是否存在,都会执行后面方法。若后面方法返回newValue为NULL,则会从Map中remove(key),若返回newValue不为NULL,则put(key,newValue),简单一句话:newValue有值则插入更新,无值就删除该key
  2. computeIfPresent(): 当key存在的时候,才会执行后面方法。
  3. computeIfAbsent(): 当key不存在的时候,才会执行后面方法。
  4. merge(key,value,function): 当key不存在的时候,直接put(key,value),若key存在,则执行function方法。

2. 代码例子以及源码解析:

1. compute()

  1. 代码例子

    public class demo {
        public static void main(String[] args) {
            Map<String, String> map = new HashMap<>();
            map.put("1", "1");
            map.put("2", "2");
            map.put("3", "3");
            // compute():无论key是否存在,都会执行BiFunction
            // 1. 当key不存在map时,则会存入map中
            // 2. 当value返回null时,会从map中remove掉该key
            // 3. 只要BiFunction返回值不为null,则都会put(key,newValue);
            map.compute("1", (k, v) -> null);
            map.compute("2", (k, v) -> k + "-" + v);
            map.compute("5", (k, v) -> k);
            System.out.println(map);
    
        }
    }
    
    

    在这里插入图片描述

2. 源码:

 default V compute(K key,
            BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
        // 传入的Function不能为空
        Objects.requireNonNull(remappingFunction);
        // 先拿key对应的value
        V oldValue = get(key);
			 // 直接执行function里面的方法,无加任何条件
        V newValue = remappingFunction.apply(key, oldValue);
        // 若newValue返回是空
        if (newValue == null) {
            // delete mapping
            if (oldValue != null || containsKey(key)) {
                // something to remove
                // 且map中key对应value有值
                // 则删除该key
                remove(key);
                return null;
            } else {
                // nothing to do. Leave things as they were.
                return null;
            }
        } else {
            // add or replace old mapping
            // 若newValue不为null,则插入替换该value值
            put(key, newValue);
            return newValue;
        }
    }

2. computeIfPresent()

  1. 代码例子

    public class demo {
        public static void main(String[] args) {
            Map<String, String> map = new HashMap<>();
            map.put("1", "1");
            map.put("2", "2");
            map.put("3", "3");
            // computeIfPresent():当key存在的时候,都会执行后面方法
            // 1. key 存在才会执行后面方法
            // 2. newValue为null,则remove()
            // 3. newValue不为null,则put(key,newValue)
            map.computeIfPresent("1", (k, v) -> null);
            map.computeIfPresent("2", (k, v) -> k + "---" + v);
            map.computeIfPresent("5", (k, v) -> k);
            System.out.println(map);
    
        }
    }
    

    在这里插入图片描述

  2. 源码

    default V computeIfPresent(K key,
                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
            Objects.requireNonNull(remappingFunction);
            V oldValue;
            // 相对于compute(),新增一个判断条件
            // 若oldValue不为空才执行Function方法
            if ((oldValue = get(key)) != null) {
                V newValue = remappingFunction.apply(key, oldValue);
                if (newValue != null) {
                    put(key, newValue);
                    return newValue;
                } else {
                    remove(key);
                    return null;
                }
            } else {
                return null;
            }
        }
    

3. computeIfAbsent()

  1. 代码例子:

    public class demo {
        public static void main(String[] args) {
            Map<String, String> map = new HashMap<>();
            map.put("1", "1");
            map.put("2", "2");
            map.put("3", "3");
            // computeIfAbsent():当key不存在的时候,都才会执行后面方法
            // 因为key不存在,固然没 k,v 因此function并不是(k,v)结构
            // 1. key 不存在才会执行后面方法
            // 2. newValue不为null,则put(key,newValue)
            map.computeIfAbsent("1", e -> "111");
            map.computeIfAbsent("5", e -> e + "-" + e);
            System.out.println(map);
    
        }
    }
    

    在这里插入图片描述

  2. 源码

    default V computeIfAbsent(K key,
                Function<? super K, ? extends V> mappingFunction) {
            Objects.requireNonNull(mappingFunction);
            V v;
            // 若value为null,才执行function方法
            if ((v = get(key)) == null) {
                V newValue;
                if ((newValue = mappingFunction.apply(key)) != null) {
                // 且当返回的newValue不为null,则插入替换原来value值
                    put(key, newValue);
                    return newValue;
                }
            }
    
            return v;
        }
    

4.merge()

  1. 代码例子

    public class demo {
        public static void main(String[] args) {
            Map<String, String> map = new HashMap<>();
            map.put("1", "1");
            map.put("2", "2");
            map.put("3", "3");
            // merge(key,value,function):
            // 1. 当get(key)为null的时候,直接put(key,value)
            // 2. 当key存在的时候,执行function方法,newValue为null,则remove(key),反之 put(key,newValue);
            map.merge("1", "1", (k, v) -> k + "-" + v);
            map.merge("5", "5", (k, v) -> k + "-" + v);
            System.out.println(map);
        }
    }
    

    在这里插入图片描述

  2. 源码

    default V merge(K key, V value,
                BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
            Objects.requireNonNull(remappingFunction);
            Objects.requireNonNull(value);
            V oldValue = get(key);
            // 先判断map中是否有对应的值
            // 有则执行function方法
            // 无则put(key,value)
            V newValue = (oldValue == null) ? value :
                       remappingFunction.apply(oldValue, value);
            if(newValue == null) {
                remove(key);
            } else {
                put(key, newValue);
            }
            return newValue;
        }
    
<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`但限定键存在时的行为 | ####
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值