深入掌握Map的这8个操作方法,让代码更简洁优雅
Map 是我们经常使用的数据结构接口,它的子类 HashMap、ConcurrentHashMap 也是我们使用比较频繁的集合。
了解了 Map 接口中的方法,也就相当于知道了其子类中的可用方法,管它是不是并发类。
自 JDK 8 起,Map 引入了一些新的方法,显著提升了对数据操作的便利性和代码可读性。随着 JDK 的发展,最新的版本已更新到 21,这些在 JDK 8 中新增的方法虽已不算 “新”,但如果你还未熟练掌握,可就真的 “落后” 了!
这几个方法其实之前说过,为什么这次再次说,因为重要的事情讲三遍,记不住就再来一遍。
HashMap 中非常好用又经常被忽略的方法
1.getOrDefault
用途:根据指定键获取值,如果键不存在,则返回默认值。
示例代码:
java
Map<String, String> map = new HashMap<>(4);
map.put("123", "123");
String key = "key";
String defaultValue = "defaultValue";
// 传统写法
String oldValue = defaultValue;
if (map.containsKey(key)) {
oldValue = map.get(key);
}
// 输出:defaultValue = defaultValue,realValue=null
System.out.println("defaultValue = " + oldValue + ",realValue=" + map.get(key));
// 优雅写法
String newValue = map.getOrDefault(key, defaultValue);
// 输出:defaultValue = defaultValue,realValue=null
System.out.println("defaultValue = " + newValue + ",realValue=" + map.get(key));
优点:减少了对 containsKey 的显式调用,简化了代码逻辑。
2.forEach
用途:更方便地遍历 Map 中的键值对。
示例代码:
java
Map<String, String> map = new HashMap<>(4);
map.put("111", "111");
// 传统写法
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.printf("key = %s, value = %s%n", entry.getKey(), entry.getValue());
}
// 简洁写法
map.forEach((key, value) -> System.out.printf("key = %s, value = %s%n", key, value));
优点:代码更简洁,直接通过 Lambda 表达式操作。
3.merge
用途:用于合并键值对,根据指定的逻辑更新或插入值。
工作原理:如果键存在,应用合并函数计算新值,并更新到 Map 中。如果键不存在,将键值对直接插入到 Map 中。
示例代码:
java
Map<String, Integer> map = new HashMap<>(8);
List<String> list = Arrays.asList("a", "b", "c");
// 传统写法
for (String item : list) {
if (map.containsKey(item)) {
map.put(item, map.get(item) + 1);
} else {
map.put(item, 1);
}
}
System.out.println(map); // 输出:{a=1, b=1, c=1}
Map<String, Integer> map1 = new HashMap<>(8);
// 简洁写法
for (String item : list) {
map1.merge(item, 1, Integer::sum);
}
System.out.println(map1); // 输出:{a=1, b=1, c=1}
优点:用一行代码即可实现计数逻辑,避免显示检查,简化复杂流程。
4.putIfAbsent
用途:仅在键不存在或值为 null 时,插入新的键值对。
示例代码:
java
Map<String, Integer> map = new HashMap<>(4);
map.put("Jim", 5);
map.put("Lily", 10);
// 传统写法
if (!map.containsKey("Lily")) {
map.put("Lily", 10);
}
// 简洁写法
map.putIfAbsent("Jim", 5);
System.out.println(map); // 输出:{Lily=10, Jim=5}
优点:避免重复检查逻辑,使代码更加直观。
5.compute
用途:通过函数对键对应的值进行动态计算。
典型应用场景:计数或根据复杂逻辑更新值。
示例代码:
java
Map<String, Integer> map = new HashMap<>(8);
List<String> list = Arrays.asList("a", "b", "c");
// 传统写法
for (String item : list) {
if (map.containsKey(item)) {
map.put(item, map.get(item) + 1);
} else {
map.put(item, 1);
}
}
System.out.println(map); // 输出:{a=1, b=1, c=1}
Map<String, Integer> map1 = new HashMap<>(8);
// 优雅写法
for (String item : list) {
map1.compute(item, (k, v) -> (v == null)? 1 : v + 1);
}
System.out.println(map1); // 输出:{a=1, b=1, c=1}
优点:逻辑内聚,避免外部重复判断。
6.computeIfAbsent
用途:当键不存在时,才通过计算生成值并插入。
示例代码:
java
Map<Integer, Integer> map = new ConcurrentHashMap<>(16);
map.put(0, 1);
map.put(1, 1);
// 传统写法,先显式检查键是否存在,然后进行插入或计算。
if (!map.containsKey(5)) {
map.put(5, Integer.sum(map.get(0), map.get(1)));
}
System.out.println(map); // 输出:{0=1, 1=1, 5=2}
// 优雅写法
map.computeIfAbsent(3, i -> Integer.sum(map.get(0), map.get(1)));
System.out.println(map); // 输出:{0=1, 1=1, 3=2, 5=2}
优点:避免显式检查键是否存在,逻辑更清晰。
7.computeIfPresent
用途:仅当键存在时,才通过计算更新值。
示例代码:
java
Map<String, Integer> map = new HashMap<>(4);
map.put("a", 10);
map.put("b", 5);
// 传统写法:显式判断键是否存在
if (map.containsKey("a")) {
Integer newScore = map.get("a") + 10;
map.put("a", newScore);
}
System.out.println(map); // 输出:{a=20, b=5}
// 简洁写法:使用 computeIfPresent
map.computeIfPresent("b", (k, v) -> v + 10);
System.out.println(map); // 输出:{a=20, b=15}
优点:自动检查键是否存在并进行更新,逻辑简洁且代码量减少。
注意:Absent 意为缺席的,present 意为目前的。computeIfAbsent 是键不存在时做处理,computeIfPresent 是键存在时做处理,两个刚好相反。
8. replace
用途:键存在时,更新值;键不存在时,不做任何操作。
示例代码:
java
Map<String, String> map = new HashMap<>();
map.put("key", "oldValue");
// 传统写法:检查键是否存在,然后更新
if (map.containsKey("key")) {
map.put("key", "newValue");
}
System.out.println(map); // 输出:{key=newValue}
// 使用 replace 方法直接更新
map.replace("key", "newValue11");
System.out.println(map); // 输出:{key=newValue11}
优点:使用 replace 方法的优势在于代码更加简洁,且自动处理键存在时的更新,如果键不存在,则不执行任何操作,避免了不必要的显式键检查。
最后总结
通过掌握这些方法,我们可以在以下场景中显著提高开发效率:
避免不必要的覆盖 (putIfAbsent、replace)
提供默认值以简化逻辑 (getOrDefault)
灵活处理键值更新 (merge、compute、computeIfPresent、computeIfAbsent)
高效遍历或批量操作 (forEach)
这些方法虽然使用频率不如基础操作,但在特定需求下往往能提供更清晰、简洁的代码逻辑。希望大家在实际开发中多加利用,写出更优雅的代码!
深入掌握Map的这8个操作方法,让代码更简洁优雅的更多相关文章
- Google Map API V3开发(6) 代码
Google Map API V3开发(1) Google Map API V3开发(2) Google Map API V3开发(3) Google Map API V3开发(4) Google M ...
- 代码中函数、变量、常量 / bss段、data段、text段 /sct文件、.map文件的关系[实例分析arm代码(mdk)]
函数代码://demo.c #include<stdio.h> #include<stdlib.h> , global2 = , global3 = ; void functi ...
- List<Map>中根据map的同一指标项数据——去重代码
先看网络上,博客经常出现的错误代码: for(ABatchAddCheckVO aBatchAddCheckVO : addList){ dto.put("aac001",aBat ...
- UFT对于PDF 文档的操作方法 VBS代码
1.首先需要安装Adobe Acrobat,而不是Adobe Reader 2.理解AcroExch.App .AcroExch.AVDoc.AcroExch.PODoc App 主要管理应用级别的对 ...
- d3.js 入门指南
说到数据可视化,我们会行到很多优秀的框架,像echarts.highcharts,这些框架很优雅,健壮,能满足我们对可视化的大部分需求,但是缺点也很明显,就是这些框架几乎是不可定制化的,当遇到特殊的需 ...
- [python基础知识]python内置函数map/reduce/filter
python内置函数map/reduce/filter 这三个函数用的顺手了,很cool. filter()函数:filter函数相当于过滤,调用一个bool_func(只返回bool类型数据的方法) ...
- 泛函编程(14)-try to map them all
虽然明白泛函编程风格中最重要的就是对一个管子里的元素进行操作.这个管子就是这么一个东西:F[A],我们说F是一个针对元素A的高阶类型,其实F就是一个装载A类型元素的管子,A类型是相对低阶,或者说是基础 ...
- Java集合的Stack、Queue、Map的遍历
Java集合的Stack.Queue.Map的遍历 在集合操作中,常常离不开对集合的遍历,对集合遍历一般来说一个foreach就搞定了,但是,对于Stack.Queue.Map类型的遍历,还是有一 ...
- 使用java8的lambda将list转为map(转)
常用方式 代码如下: public Map<Long, String> getIdNameMap(List<Account> accounts) { return accoun ...
- 在JavaScript函数式编程里使用Map和Reduce方法
所有人都谈论道workflows支持ECMAScript6里出现的令人吃惊的新特性,因此我们很容易忘掉ECMAScript5带给我们一些很棒的工具方法来支持在JavaScript里进行函数编程,这些工 ...
随机推荐
- IM开发干货分享:IM客户端不同版本兼容运行的技术思路和实践总结
本文由巩鹏军分享,原题"IM兼容性基建",本文有修订. 1.引言 一个成熟的IM成品,在运营过程中随着时间的推移,会发布不同的版本,但为了用户体验并不能强制要求用户必须升级到最新版 ...
- 使用format_obproxy_digest_log工具分析obproxy网络层耗时SQL
之前写过一个博客,介绍 ob_tools包 来实施抓取 observer 层的 gv$ob_sql_audit 的SQL,还提供一些分析SQL来通过不同维度分析缓慢的业务SQL语句,免得和应用扯皮说数 ...
- ATM 管理系统的设计与实现(类似毕业设计,附源代码)
ATM 管理系统的设计与实现 作者前言:本系统通过基本规范化的设计,简单的利用了java基本功能实现了ATM系统,本系统虽然简单,但是逻辑很严密,对于有一定java知识的读者有较大帮助,可以用作参考. ...
- Solution Set -「PTS Simus」“待天地再静默一秒”
目录 03.11 A. 太阳照常升起 (exam) B. 丧钟为谁而鸣 (exam) C. 老人与海 (exam) 03.12 A. 「计蒜客 #42547」Yuuki and a problem B ...
- 【Docker】---部署集群(2)
RocketMQ(2)-Docker集群部署RocketMQ =前言= 1.因为自己只买了一台阿里云服务器,所以RocketMQ集群都部署在单台服务器上只是端口不同,如果实际开发,可以分别部署在多台服 ...
- tmux中的vim无法多彩高亮显示关键字
1. 问题描述 vim安装了interastingwords插件,在mobaxterm中的session可以正常显示多彩关键字,但是使用tmux登录session,只能显示两个颜色 2. 解决办法 这 ...
- 基于C#实现多线程启动停止暂停继续
大家好!我是付工. 大部分初学者在学习C#上位机编程时,多线程是一个很难逾越的鸿沟,不合理地使用多线程,会导致经常出现各种奇怪的问题,这也是很多初学者不敢使用多线程的原因.但是在实际开发中,多线程是一 ...
- nginx basic验证
打开个生成htpasswd的网站 输入信息生成结果 将结果保存到nginx一个文件里面 修改nginx的conf文件 auth_basic "webA"; #这个"&qu ...
- PHP常量与数据类型
PHP常量与数据类型 PHP常量 在PHP中,常量是值在脚本执行期间不会改变的量.常量使用define()函数或const关键字来定义. 使用define()函数: define("GREE ...
- Whois 收集
Whois 收集 Whois是什么 Whois(读作"Who is")是一个标准的互联网协议,主要用于查询域名的注册信息,包括域名所有人.注册商.注册时间.过期时间等详细信息.简单 ...