Java 8 最大的特性无异于更多地面向函数,比如引入了 lambda等,可以更好地进行函数式编程。前段时间无意间发现了 map.merge() 方法,感觉还是很好用的,此文简单做一些相关介绍。首先我们先看一个例子。
一:merge() 怎么用?
假如现在我们有个集合,集合中存放了各个学生各科的成绩,现在需要按学生敏子统计这个学生各科成绩的总分。
class StudentScore {
private String name;
private String subject;
private Integer score;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public Integer getScore() {
return score;
}
public void setScore(Integer score) {
this.score = score;
}
public StudentScore(String name, String subject, Integer score) {
this.name = name;
this.subject = subject;
this.score = score;
}
}
/*
* @Author :chuxia0811
* @Date: 2021/3/6 18:11
* @Param:生成所有学生各科的成绩集合
* @Return:
* @Description :
*/
public List<StudentScore> scoreinit() {
List<StudentScore> scoreList = new ArrayList<>();
scoreList.add(new StudentScore("张三", "java", 90));
scoreList.add(new StudentScore("张三", "python", 95));
scoreList.add(new StudentScore("张三", "php", 80));
scoreList.add(new StudentScore("李四", "java", 88));
scoreList.add(new StudentScore("李四", "python", 70));
scoreList.add(new StudentScore("李四", "php", 98));
scoreList.add(new StudentScore("王五", "java", 89));
scoreList.add(new StudentScore("王五", "python", 76));
scoreList.add(new StudentScore("王五", "php", 70));
return scoreList;
}
我们首先来看下常规的统计方法:
/**
* @Author :chuxia0811
* @Date: 2021/3/6 18:19
* @Param: 常规做法
* @Return:
* @Description :
*/
public void test1() {
ObjectMapper objectMapper = new ObjectMapper();
List<StudentScore> scores = scoreinit();
Map<String,Integer> map = new HashMap<>();
scores.forEach(score -> {
if (map.containsKey(score.getName())){
map.put(score.getName(),map.get(score.getName())+score.getScore());
}else {
map.put(score.getName(),score.getScore());
}
});
try {
System.out.println(objectMapper.writeValueAsString(map));
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
打印结果如下:
{"李四":256,"张三":265,"王五":235}
我们再看下用merge()方法:
/*
* @Author :chuxia0811
* @Date: 2021/3/6 19:18
* @Param:merge()方法
* @Return:
* @Description :
*/
public void test2(){
ObjectMapper objectMapper = new ObjectMapper();
Map<String,Integer> map = new HashMap<>();
List<StudentScore> scores = scoreinit();
scores.forEach(score -> map.merge(score.getName(),score.getScore(),Integer::sum));
try {
System.out.println(objectMapper.writeValueAsString(map));
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
打印结果如下:
public static void main(String[] args) {
Merge merge = new Merge();
merge.test1();
merge.test2();
}
{"李四":256,"张三":265,"王五":235}
{"李四":256,"张三":265,"王五":235}
可以看出,结果一样,但用merge()方法会简单很多代码。
二:merge() 方法简介
merge() 可以这么理解:它将新的值赋值到 key (如果不存在)或更新给定的key 值对应的 value,其源码如下:
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;
}
我们可以看到原理也是很简单的,该方法接收三个参数,一个 key 值,一个 value,一个 remappingFunction ,如果给定的key不存在,它就变成了 put(key, value) 。
但是,如果 key 已经存在一些值,我们 remappingFunction 可以选择合并的方式,然后将合并得到的 newValue 赋值给原先的 key。
三:使用场景
这个使用场景相对来说还是比较多的,比如分组求和这类的操作,虽然 stream 中有相关 groupingBy() 方法,但如果你想在循环中做一些其他操作的时候,merge() 还是一个挺不错的选择的。
四:其他补充
除了 merge() 方法之外,我还看到了一些Java 8 中 map 相关的其他方法,比如 putIfAbsent 、compute() 、computeIfAbsent() 、computeIfPresent,这些方法我们看名字应该就知道是什么意思了,故此处就不做过多介绍了,感兴趣的可以简单阅读一下源码(都还是挺易懂的)。