1、上代码之前我们先上源码,然后做一下分析:
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;
}
通过对上面的源码分析,我想不管是初级程序猿还是老司机,大家都可以看懂,merge函数,就是每次拿Map里面key的oldValue和新传递的value进行函数运算,具体什么运算方式和传递的函数类型有关,如果你传递的是sum,那么就是oldValue和参数value相加,最后将sum结果put到当前Map对象中。分析到这里大家是不是就发现了新大陆。当然该函数也对你传递的value和funciton做了限制,就是非空,一旦为null就会抛出异常。
2、下面是实例代码
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* chen.kai
* 测试 集合(list,set)中分组的sum,count
*/
public class Test {
static class Persion {
//姓名
private String name;
//年龄
private Integer age;
//身高
private Double height;
//财产
private BigDecimal asset;
public Persion (String name, Integer age, Double height) {
this.name = name;
this.age = age;
this.height = height;
}
public Persion (String name, Integer age, Double height, BigDecimal asset) {
this(name, age, height);
this.asset = asset;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Double getHeight() {
return height;
}
public void setHeight(Double height) {
this.height = height;
}
public BigDecimal getAsset() {
return asset;
}
public void setAsset(BigDecimal asset) {
this.asset = asset;
}
}
//分组聚合测试
public static void main(String[] args) {
List<Persion> list = new ArrayList<>();
list.add(new Persion("张三", 20, 176.5));
list.add(new Persion("李四", 25, 175.0, new BigDecimal(1000)));
list.add(new Persion("王五", 25, 170.0, new BigDecimal("2000.53")));
list.add(new Persion("丁六", 20, 176.5, new BigDecimal(2000)));
list.add(new Persion("戊七", 30, 169.3, new BigDecimal("10000.99")));
//求出每个年龄的所有资产,从肉眼看有三条数据,那我们测试一下,看是否处理正确,其中张三的asset = null,这是一个很敏感的数据
Map<Integer, BigDecimal> map1 = new HashMap<>();
for (Persion p : list) {
map1.merge(p.getAge(), p.getAsset(), BigDecimal::add);
}
System.out.println(map1.toString());
}
运行结果如下:
动动你们的小脑筋,为什么会报错呢?我们上面分析源码是不是说过,该函数对传递的参数有一定的限制,就是value和function必须非空,但是张三数据的asset=null,ok,找到了问题,那么我们改变写法,写一个三目表达式,解决问题,
//分组聚合测试
public static void main(String[] args) {
List<Persion> list = new ArrayList<>();
list.add(new Persion("张三", 20, 176.5));
list.add(new Persion("李四", 25, 175.0, new BigDecimal(1000)));
list.add(new Persion("王五", 25, 170.0, new BigDecimal("2000.53")));
list.add(new Persion("丁六", 20, 176.5, new BigDecimal(2000)));
list.add(new Persion("戊七", 30, 169.3, new BigDecimal("10000.99")));
//求出每个年龄的所有资产,从肉眼看有三条数据,那我们测试一下,看是否处理正确,其中张三的asset = null,这是一个很敏感的数据
Map<Integer, BigDecimal> map1 = new HashMap<>();
for (Persion p : list) {
map1.merge(p.getAge(), p.getAsset() == null ? BigDecimal.ZERO : p.getAsset(), BigDecimal::add);
}
System.out.println(map1.toString());
}
运行结果如下,答案完全正确,完美解决:
3、多列分组,sum测试:
//分组聚合测试
public static void main(String[] args) {
List<Persion> list = new ArrayList<>();
list.add(new Persion("张三", 20, 176.5));
list.add(new Persion("李四", 25, 175.0, new BigDecimal(1000)));
list.add(new Persion("王五", 25, 170.0, new BigDecimal("2000.53")));
list.add(new Persion("丁六", 20, 176.5, new BigDecimal(2000)));
list.add(new Persion("戊七", 30, 169.3, new BigDecimal("10000.99")));
list.add(new Persion("李一", 30, 169.3, new BigDecimal("20000.11")));
//求出每个年龄段,每个身高的资产情况
Map<String, BigDecimal> map = new HashMap<>();
for (Persion p : list) {
map.merge(p.getAge() + "_" + p.getHeight(), p.getAsset() == null ? BigDecimal.ZERO : p.getAsset(), BigDecimal::add);
}
System.out.println(map.toString());
}
4、count,max测试
//分组聚合测试
public static void main(String[] args) {
List<Persion> list = new ArrayList<>();
list.add(new Persion("张三", 20, 176.5));
list.add(new Persion("李四", 25, 175.0, new BigDecimal(1000)));
list.add(new Persion("王五", 25, 170.0, new BigDecimal("2000.53")));
list.add(new Persion("丁六", 20, 176.5, new BigDecimal(2000)));
list.add(new Persion("戊七", 30, 169.3, new BigDecimal("10000.99")));
list.add(new Persion("李一", 30, 169.3, new BigDecimal("20000.11")));
//count合计,求出每个年龄段有多少人
Map<Integer, Integer> map3 = new HashMap<>();
for (Persion p: list) {
map3.merge(p.getAge(), 1, Integer::sum);
}
System.out.println("count合计:" + map3.toString());
//max,求出每个年龄段最大身高
Map<Integer, Double> map4 = new HashMap<>();
for (Persion p: list) {
map4.merge(p.getAge(), p.getHeight(), Double::max);
}
System.out.println("求max:" +map4.toString());
}
运行结果安全无误: