1. 简介

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

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 (添加/更新元素)
@Test
public 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=李四)
}
  1. key和value可以为null (hashmap 和 linkedhashmap)
  2. 使用null可以正常的覆盖和获取元素
  3. put可以直接新增or覆盖已有的元素
  4. put方法返回对应key的oldValue,如果没有oldValue则返回null

2.3 getOrDefault

// getOrDefault(Object key, V defaultValue) (获取/返回默认值)
@Test
public 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=张铁牛)
}
  1. 当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) (如果不存在则添加)
@Test
public 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=李四)
}
  1. 如果指定的key对应的value不为null时(oldValue != null) : 不覆盖 & 返回oldValue
  2. 当指定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) (计算)
@Test
public 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
}
  1. remappingFunction返回值 != null : 覆盖oldValue & 返回newValue
  2. 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) (不存在则计算)
@Test
public 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
}
  1. oldValue != null : 不覆盖 & 返回oldValue
  2. oldValue == null && mappingFunction返回值 != null: 添加元素 & 返回newValue
  3. oldValue == null && mappingFunction返回值 == null: 不覆盖 & 返回oldValue

可以理解为 当指定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) (存在则计算)
@Test
public 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
}
  1. oldValue == null : 不覆盖&返回null
  2. oldValue != null && remappingFunction返回值 == null : 移除元素&返回null
  3. 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) (替换)
@Test
public 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=张铁牛)}
}
  1. 替换指定key的value值
  2. 可以将对应的value设置为null
  3. 对应的key不存在时不会添加新元素
  4. 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) (融合)
@Test
public 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=李四)
}
  1. oldValue == null : 使用传进来的 value 作为newValue, oldValue != null : 使用remappingFunction的返回值作为newValue

    • newValue == null : 移除元素 & 返回newValue

    • newValue != null : 覆盖元素 & 返回newValue

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

  1. key对应的value(oldValue)
  2. merge方法的第二个参数value (可以理解为oldValue的defaultValue)
  3. 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 新增
@Test
public 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. 总结

方法名称 方法参数 方法描述 方法特点
put key, value 添加元素 hashmap/linkedhashmap: key, value 都可以为null
getOrDefault key, defaultValue 获取元素 当map中没有对应的key时, 返回defaultValue
putIfAbsent key, value 当不存在时添加元素 这里不存在指的是: key对应的旧值为null
compute key, BiFunction<key, oldValue, newValue> remappingFunction 重新计算key对应的value 使用remappingFunction的返回值替换key的旧值
computeIfAbsent key, Function<key, value> mappingFunction 当不存在时计算 这里不存在指的是: key对应的旧值为null, 与putIfAbsent方法逻辑类似
computeIfPresent key, BiFunction<key, oldValue, newValue> remappingFunction 当存在时计算 这里存在指的是: key对应的旧值!=null
replace key, value 替换元素 替换指定key的value, 不会添加元素
merge key, value, BiFunction<oldValue, value, newValue> remappingFunction 融合 融合key的旧值, 默认值, remappingFunction的返回值作为新值
foreach BiConsumer<key, value> 遍历 java8新加的遍历方式

Map中经常被忽略但又非常好用的方法的更多相关文章

  1. Map java中的map 如何修改Map中的对应元素

    Map java中的map 如何修改Map中的对应元素 Map以按键/数值对的形式存储数据,和数组非常相似,在数组中存在的索引,它们本身也是对象.         Map的接口         Map ...

  2. 自定义注解+反射提取对象到map中

    一.问题:有时候我们与第三方接口对接传参时,需要将对象里的字段和值以map形式传给别人,此时可以借助其他的工具类,但是我个人用起来不太灵活,还会把多余的字段传给别人,因此我们自己动手搞一套 二.思路: ...

  3. jsp页面使用el 按key获取map中的对应值

    jsp页面使用el 按key获取map中的对应值 转自:<jsp页面使用el 按key获取map中的对应值>地址:http://blog.csdn.net/baple/article/de ...

  4. 3. 如何封装查询条件与查询结果到map中

    public Map<String, Object> queryOrderStatus(String orderNo) { // 查询到的结果与查询的条件一一对应,封装到map中! Str ...

  5. Java根据条件删除Map中元素

    今天在写程序过程中,需要根据判断条件删除一个Map中的相应数据,我自然而然想到可以通过调用Map中的remove(Object key)函数进行删除:代码如下: public Map<Doubl ...

  6. Map中如何把没有定义操作符<的类作为key

    Map中如何把没有定义操作符<的类作为key 其实,为了实现快速查找,map内部本身就是按序存储的(比如红黑树).在我们插入<key, value>键值对时,就会按照key的大小顺序 ...

  7. 对象属性封装到map中

    import java.beans.PropertyDescriptor; import java.lang.reflect.Method; import java.lang.reflect.Modi ...

  8. map中的erase成员函数用法

    转载于 http://www.cnblogs.com/graphics/archive/2010/07/05/1771110.html  http://hi.baidu.com/sdkinger/it ...

  9. 修改Map中确定key对应的value问题

    今天在码代码的时候出现一个没有预料的问题: 先看下面的代码: public static void main(String[] args) { String[] files=new String[]{ ...

  10. Ibatis中sqlmap参数map中还需要套list的情况如何写?

    原始需求: 有若干个参数,需要作为ibatis拼装sql的参数传入,但是有个参数的值比较特殊,是若干种枚举值.具体到这个case,就是有有限个namespace.我每次需要通过传入多个namespac ...

随机推荐

  1. Java高并发,ReadWriteLock(读写锁)

    并发读写的时候,很容易造成数据不一致的状态 上案例,代码如下: public class ReadWriteLockDemo { public static void main(String[] ar ...

  2. 异源数据同步 → 如何获取 DataX 已同步数据量?

    开心一刻 今天,表妹问我:哥,我男朋友过两天要生日了,你们男生一般喜欢什么,帮忙推荐个礼物呗我:预算多少表妹:预算300我:20块买条黑丝,剩下280给自己买支口红,你男朋友生日那天你都给自己用上表妹 ...

  3. 网站安全,为什么老外如此钟爱国产 WAF?

    大家好,我是长亭雷池 WAF 社区的开发者,这段时间一直在忙着搞雷池国际版,前后搞了两三个月,总算初步有了一些收获,写个帖子和大家分享一下. 雷池 WAF 社区版 雷池 WAF 社区版是由长亭科技打造 ...

  4. AT开发FOTA远程升级:Air780EP低功耗4G模组

    ​ 针对客户朋友的应用反馈,特本篇文章:基于Air780EP模组AT开发的FOTA远程升级指南. AT版本的远程升级主要是对AT固件版本进行升级,实际方式为通过合宙官方IoT平台升级或者使用自己搭建的 ...

  5. rabbitmq消息中间件的初步探索

    在上次学xattr的时候用它简单实现一个中间件,我去了解了一下rabbitmq这个消息中间件,感觉理论上还是挺好用的,给一般并发量的系统用足够了. 首先安装这个服务. sudo apt search ...

  6. OSG开发笔记(三十四): OsgUtil::Simplifier:简化几何体,提升显示性能和渲染效率

    前言   对于一些较大的图形,会出现显示卡顿和渲染缓慢的问题,这时候就要使用到osgUtil::Simplifier简化器,来对其进行简化.   Demo            osgUtil   o ...

  7. 使用Acme.sh免费签发SSL证书

    github:https://github.com/acmesh-official/acme.sh 概述一个纯粹用Shell(Unix shell)语言编写的ACME协议客户端.完整的ACME协议实施 ...

  8. Spring Data JPA自动生成表时列顺序混乱的解决办法(最新版)

    最近把Spring Boot的版本升级到了3.3.5,突然发现一个问题:当使用Spring Data JPA自动生成表的时候,所产生的列顺序与Entity类中的变量顺序不一致了.比如,有一个下面这样的 ...

  9. LeetCode题集-6 - Z 字形变换

    题目:将一个给定字符串 s 根据给定的行数 numRows ,以从上往下.从左到右进行 Z 字形排列. 这一题作为中等难度,下面和大家分享几种不同的解法. 01.二维矩阵模拟法 所谓二维矩阵模拟法就是 ...

  10. Flutter WebView报错ERR_NAME_NOT_RESOLVED

    WebView报错ERR_NAME_NOT_RESOLVED 用的webview_flutter插件,开始都用的好好的,后面突然报错ERR_NAME_NOT_RESOLVED,上网逛了一圈说如果要用h ...