Java HashMap食用技巧

1.引言

最近一直在忙于更改之前的代码,由于项目时间线比较久,存在好多的API使用级别的优化。现在将最近在HashMap使用上的优化分享给大家。

本文将着重展示map接口的一下几个API的使用,相信要是用的好的话,可以极大的简化我们的代码。

1. putIfAbsent: 如果map不包含key,放入map, 返回旧值(null)

2. computeIfAbsent: 如果map不包含key, 初始化key所对应的value,放入map中,返回新值。方法入参 key, 返回值缺失时需要初始化的值。

3. computeIfPresent: 如果map中包含key, 执行自定义的函数操作,否则返回null。方法入参当前操作的key和key对应的旧值(不会是null),返回值根据一定规则merge的值。

4.compute: 相当于2,3 的通用版,将控制权交给用户了,用户可以自定义自己的逻辑。方法入参当前操作的key和key对应的旧值(可能是null),返回值根据一定规则merge的值。

下面我会通过一些例子来加深大家对这几个API的理解。

2.发现重复key时不放入

>  老代码

Map<String, String> map = new HashMap<>();
if(!map.containsKey("key")) map.put("key", "val");

> 修正版

Map<String, String> map = new HashMap<>();
map.putIfAbsent("key", "val");

3. 数据分组存入Map

> 老代码

Map<String, List<Employee>> map = new HashMap<>();
for(Employee employee: employees) {
	if(!map.containsKey(employee.getName())) {
		List<Employee> list = new ArrayList<>();
		list.add(employee);
		map.put(employee.getName(), list);
	}else {
		map.get(employee.getName()).add(employee);
	}
}

> 修正版

1) putIfAbsent版本

Map<String, List<Employee>> map = new HashMap<>();
employees.forEach(employee -> {
	// putIfAbsent 返回旧值(可能是null), 无法实现in-line调用
    map.putIfAbsent(employee.getName(), new ArrayList<>());
	map.get(employee.getName()).add(employee);
});

2) computeIfAbsent版本

Map<String, List<Employee>> map = new HashMap<>();
// 利用computeIfAbsent返回新值特性,实现in-line方法调用
employees.forEach(employee -> map.computeIfAbsent(employee.getName(), key -> new ArrayList<>()).add(employee));

3) computeIfPresent版本

Map<String, List<Employee>> map = new HashMap<>();
employees.forEach(employee -> {
	// 合并重复key
	List<Employee> list = map.computeIfPresent(employee.getName(), (key, value) -> {
		value.add(employee);
		return value;
	});
	// 第一次放{key, value}
	if (Objects.isNull(list)) {
		map.put(employee.getName(), Stream.of(employee).collect(Collectors.toList()));
	}
});

4) compute版本

Map<String, List<Employee>> map = new HashMap<>();
employees.forEach(employee -> 
     // 处理value初始化, 利用compute返回新值特性,实现in-line方法调用
     map.compute(employee.getName(), (key, value) -> Objects.isNull(value) ? new ArrayList<>() : value)
	 // 添加分组内的元素	
        .add(employee));

综上,computeIfAbsent和compute在代码风格上更简洁,而computeIfAbsent更加适配上面的情形。编程就应该朝着简洁高效的方向进行,这是所有编程语言共通的。

4. 数据分组汇总(求和)

>老代码

Map<String, Double> map = new HashMap<>();
for (Employee employee : employees) {
	if (!map.containsKey(employee.getName())) {
		map.put(employee.getName(), employee.getSalary());
	} else {
		double merged = map.get(employee.name) + employee.getSalary();
		map.put(employee.getName(), merged);
	}
}

>修正版

1) putIfAbsent 版本

Map<String, Double> map = new HashMap<>();
employees.forEach(employee -> {
	// 注意这里使用包装类型
	Double previous = map.putIfAbsent(employee.getName(), employee.getSalary());
	// 借助 putIfAbsent 返回旧值,追溯当前key的前一次累加值
	if (Objects.nonNull(previous)) map.put(employee.getName(), previous + employee.getSalary());
});

2) computeIfAbsent 版本

Map<String, Double> map = new HashMap<>();
employees.forEach(employee -> {
	// computeIfAbsent 每次返回新值,需要处理第一次和不是第一次的情况,否则就造成数据丢失
	double previous = map.computeIfAbsent(employee.getName(), key -> map.containsKey(key) ? map.get(key) : 0.0);
	map.put(employee.getName(), previous + employee.getSalary());
});

3) computeIfPresent 版本

Map<String, Double> map = new HashMap<>();
employees.forEach(employee -> {
	// computeIfPresent 完成数据汇总
	map.computeIfPresent(employee.getName(), (key, value) -> value + employee.getSalary());
	// putIfAbsent 完成第一次key值放入
	map.putIfAbsent(employee.getName(), employee.getSalary());
});

4) compute 版本

Map<String, Double> map = new HashMap<>();
employees.forEach(
		// 利用compute 自己定义merge规则,实现方法in-line调用
		employee -> map.compute(employee.getName(),
				               (key, value) -> Objects.isNull(value) ? employee.getSalary() : value + employee.getSalary()
				               )
		);

综上,在根据key合并value时,compute提供了很好的优化能够达到in-line调用。

5.结尾

本篇文章主要是就Java8提供的新的Map接口做了一些demo, 相信大家如果能灵活应用这些API,一定可以简化map数据的构造过程。不过任何事情都不是一蹴而就的,还是需要在实际开发中多多使用才能达到熟能生巧,融会贯通,极大简化Java代码(Java 过于繁复的语言结构一直为人所诟病,这也算是一次小小的优化了)。

最后各位如果感觉这篇文章对你们有帮助的话,请动一下你们的右手食指,点个赞哈。本人在此感谢各位看官了。

  • 12
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值