diannao 发表于 2025-2-7 00:09:52

Map中经常被忽略但又非常好用的方法

1. 简介

map是我们日常开发中常会的集合类之一, 但是我们除了常用的get和put之外,其他的方法好像很少会用到,接下来我们就介绍一下几个经常被忽略但又很好用的方法.
2. Quick Start

2.1 数据准备

创建一个map对象, 并声明几个用于测试的user对象
Map<Integer, User> hashMap = Maps.newHashMap();User zhangsan = new User(1, "张三");User lisi = new User(2, "李四");User zhangtieniu = new User(3, "张铁牛");2.2 重温put

// hashmap put (添加/更新元素)@Testpublic void put() {    User test = hashMap.put(null, null);    User user = hashMap.put(1, null);    User user1 = hashMap.put(1, zhangsan);    User user2 = hashMap.put(1, lisi);    User user3 = hashMap.put(null, zhangsan);    User user4 = hashMap.put(null, lisi);    User user5 = hashMap.get(null);    log.info("map: {}", hashMap);    log.info("user: {}, user1: {}, user2: {}, user3: {}, user4: {}, user5: {}", user, user1, user2, user3, user4, user5);    //map: {null=User(id=2, name=李四), 1=User(id=2, name=李四)}    //user: null, user1: null, user2: User(id=1, name=张三), user3: null, user4: User(id=1, name=张三), user5: User(id=2, name=李四)}
[*]key和value可以为null (hashmap 和 linkedhashmap)
[*]使用null可以正常的覆盖和获取元素
[*]put可以直接新增or覆盖已有的元素
[*]put方法返回对应key的oldValue,如果没有oldValue则返回null
2.3 getOrDefault

// getOrDefault(Object key, V defaultValue) (获取/返回默认值)@Testpublic void getOrDefault() {    hashMap.put(1, zhangsan);    hashMap.put(2, null);    final User user1 = hashMap.get(1);    final User user2 = hashMap.getOrDefault(2, lisi);    final User user3 = hashMap.getOrDefault(3, zhangtieniu);    log.info("map: {}", hashMap);    //map: {1=User(id=1, name=张三), 2=null}    log.info("user1: {}, user2: {}, user3: {}", user1, user2, user3);    //user1: User(id=1, name=张三), user2: null, user3: User(id=3, name=张铁牛)}
[*]当map中没有对应的key时, 返回对应的defaultValue
注意: 如果map中存在对应的key, 但是对应的value == null时, 返回的是null, 而不是defaultValue
源码如下:
default V getOrDefault(Object key, V defaultValue) {    V v;    return (((v = get(key)) != null) || containsKey(key))      ? v      : defaultValue;}2.4 putIfAbsent

// putIfAbsent(K key, V value) (如果不存在则添加)@Testpublic void putIfAbsent() {    hashMap.put(1, null);    User user1 = hashMap.putIfAbsent(1, zhangsan);    User user2 = hashMap.putIfAbsent(2, lisi);    User user3 = hashMap.putIfAbsent(2, zhangtieniu);    log.info("map: {}", hashMap);    log.info("user1: {}, user2: {}, user3: {}", user1, user2, user3);    //map: {1=User(id=1, name=张三), 2=User(id=2, name=李四)}    //user1: null, user2: null, user3: User(id=2, name=李四)}
[*]如果指定的key对应的value不为null时(oldValue != null) : 不覆盖 & 返回oldValue
[*]当指定key的value不存在时(oldValue == null) : 添加元素 & 返回oldValue
可以理解为 当指定key的value不存在时, 才去put, 否则不添加
源码如下:
default V putIfAbsent(K key, V value) {    V v = get(key);    if (v == null) {      v = put(key, value);    }    return v;}2.5 compute

// compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) (计算)@Testpublic void compute() {    hashMap.put(1, zhangsan);    User user1 = hashMap.compute(1, (k, oldValue) -> lisi);    log.info("map: {}, user1: {}", hashMap, user1);    //map: {1=User(id=2, name=李四)}, user1: User(id=2, name=李四)    User user2 = hashMap.compute(1, (k, oldValue) -> null);    log.info("map: {}, user2: {}", hashMap, user2);    //map: {}, user2: null}
[*]remappingFunction返回值 != null : 覆盖oldValue & 返回newValue
[*]remappingFunction返回值 == null : 删除对应元素 & 返回null
可以理解为 使用remappingFunction的返回值覆盖对应key的旧值, 当remappingFunction返回值为null时, 会直接将当前元素移除掉
源码如下:
default V compute(K key,      BiFunction<? super K, ? super V, ? extends V> remappingFunction) {    Objects.requireNonNull(remappingFunction);    V oldValue = get(key);    V newValue = remappingFunction.apply(key, oldValue);    if (newValue == null) {      // delete mapping      if (oldValue != null || containsKey(key)) {            // something to remove            remove(key);            return null;      } else {            // nothing to do. Leave things as they were.            return null;      }    } else {      // add or replace old mapping      put(key, newValue);      return newValue;    }}2.6 computeIfAbsent

// computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) (不存在则计算)@Testpublic void computeIfAbsent() {    User user = hashMap.computeIfAbsent(1, k -> zhangsan);    User user1 = hashMap.computeIfAbsent(1, k -> lisi);    User user2 = hashMap.computeIfAbsent(2, k -> null);    log.info("map: {}, user:{}, user1: {}, user2:{}", hashMap, user, user1, user2);    //map: {1=User(id=1, name=张三)}, user:User(id=1, name=张三), user1: User(id=1, name=张三), user2:null}
[*]oldValue != null : 不覆盖 & 返回oldValue
[*]oldValue == null && mappingFunction返回值 != null: 添加元素 & 返回newValue
[*]oldValue == null && mappingFunction返回值 == null: 不覆盖 & 返回null
可以理解为 当指定key的value不存在时, 才使用mappingFunction的返回值覆盖对应key的旧值, 如果key对应value存在或者mappingFunction的返回值为null时, 则不覆盖
源码如下:
default V computeIfAbsent(K key,      Function<? super K, ? extends V> mappingFunction) {    Objects.requireNonNull(mappingFunction);    V v;    if ((v = get(key)) == null) {      V newValue;      if ((newValue = mappingFunction.apply(key)) != null) {            put(key, newValue);            return newValue;      }    }    return v;}2.7 computeIfPresent

// computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) (存在则计算)@Testpublic void computeIfPresent() {    hashMap.put(1, zhangsan);    User user1 = hashMap.computeIfPresent(1, (k,oldValue) -> lisi);    User user2 = hashMap.computeIfPresent(3, (k,oldValue) -> zhangtieniu);    log.info("map: {}, user1: {}, user2: {}", hashMap, user1, user2);    //map: {1=User(id=2, name=李四)}, user1: User(id=2, name=李四), user2: null    User user3 = hashMap.computeIfPresent(1, (k,oldValue) -> null);    log.info("map: {}, user3:{}", hashMap, user3);    //map: {}, user3:null}
[*]oldValue == null : 不覆盖&返回null
[*]oldValue != null && remappingFunction返回值 == null : 移除元素&返回null
[*]oldValue != null && remappingFunction返回值 != null : 覆盖元素&返回newValue
可以理解为 当key对应的value存在时, 才使用remappingFunction的返回值覆盖对应key的旧值, 如果key对应的value不存在或者remappingFunction的返回值为null时, 则不覆盖
源码如下:
default V computeIfPresent(K key,      BiFunction<? super K, ? super V, ? extends V> remappingFunction) {    Objects.requireNonNull(remappingFunction);    V oldValue;    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;    }}2.8 replace

// replace(K key, V value)// replace(K key, V oldValue, V newValue) (替换)@Testpublic void replace() {    hashMap.put(1, zhangsan);    hashMap.put(2, lisi);    hashMap.replace(1, zhangtieniu);    hashMap.replace(2, null);    hashMap.replace(3, zhangtieniu);    hashMap.replace(2, null, zhangtieniu);    log.info("map: {}", hashMap);    //map: {1=User(id=3, name=张铁牛), 2=User(id=3, name=张铁牛)}}
[*]替换指定key的value值
[*]可以将对应的value设置为null
[*]对应的key不存在时不会添加新元素
[*]replace(K key, V oldValue, V newValue)方法多了一层判断, 当key对应的value与oldValue相等时, 才会替换newValue
可以理解为 替换指定key的value值
源码如下:
default V replace(K key, V value) {    V curValue;    if (((curValue = get(key)) != null) || containsKey(key)) {      curValue = put(key, value);    }    return curValue;}default boolean replace(K key, V oldValue, V newValue) {    Object curValue = get(key);    if (!Objects.equals(curValue, oldValue) ||      (curValue == null && !containsKey(key))) {      return false;    }    put(key, newValue);    return true;}2.9 merge

// merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) (融合)@Testpublic void merge() {    hashMap.put(1, zhangsan);    User user1 = hashMap.merge(1, lisi, (oldValue, defaultValue) -> zhangtieniu);    User user2 = hashMap.merge(2, lisi, (oldValue, defaultValue) -> zhangtieniu);    log.info("map: {}, user1: {}, user2: {}", hashMap, user1, user2);    //map: {1=User(id=3, name=张铁牛), 2=User(id=2, name=李四)}, user1: User(id=3, name=张铁牛), user2: User(id=2, name=李四)}
[*]oldValue == null : 使用传进来的 value 作为newValue, oldValue != null: 使用remappingFunction的返回值作为newValue

[*]newValue == null : 移除元素 & 返回newValue
[*]newValue != null : 覆盖元素 & 返回newValue

可以理解为 融合三个值 分别为:

[*]key对应的value(oldValue)
[*]merge方法的第二个参数value (可以理解为oldValue的defaultValue)
[*]merge方法的第三个参数remappingFunction方法的返回值
融合逻辑为:如果key对应的value不存在时, 使用merge方法的第二个参数value作为newValue, 如果key对应的value存在时,使用remappingFunction的返回值作为newValue, 如果newValue不为null则覆盖元素, 为null则移除元素
源码如下:
    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);      V newValue = (oldValue == null) ? value :                   remappingFunction.apply(oldValue, value);      if(newValue == null) {            remove(key);      } else {            put(key, newValue);      }      return newValue;    }}2.10 foreach

// foreach java8 新增@Testpublic void foreach() {    hashMap.put(1, zhangsan);    hashMap.put(2, lisi);    hashMap.forEach((key, value) -> log.info("key: {}, value: {}", key, value));    //key: 1, value: User(id=1, name=张三)    //key: 2, value: User(id=2, name=李四)}3. 总结

方法名称方法参数方法描述方法特点putkey, value添加元素hashmap/linkedhashmap: key, value 都可以为nullgetOrDefaultkey, defaultValue获取元素当map中没有对应的key时, 返回defaultValueputIfAbsentkey, value当不存在时添加元素这里不存在指的是: key对应的旧值为nullcomputekey, BiFunction<key, oldValue, newValue> remappingFunction重新计算key对应的value使用remappingFunction的返回值替换key的旧值computeIfAbsentkey, Function<key, value> mappingFunction当不存在时计算这里不存在指的是:key对应的旧值为null, 与putIfAbsent方法逻辑类似computeIfPresentkey, BiFunction<key, oldValue, newValue> remappingFunction当存在时计算这里存在指的是: key对应的旧值!=nullreplacekey, value替换元素替换指定key的value, 不会添加元素mergekey, value, BiFunction<oldValue, value, newValue> remappingFunction融合融合key的旧值, 默认值, remappingFunction的返回值作为新值foreachBiConsumer<key, value>遍历java8新加的遍历方式
页: [1]
查看完整版本: Map中经常被忽略但又非常好用的方法