一、背景
在日常写代码的过程中,针对List集合,统计里面的某个属性,是经常的事情,针对List的某个属性的统计,我们目前大部分时候的代码都是这样写,每统计一个变量,就要定义一个值,且要在for循环增加一行累计的代码,比较繁琐,而且代码写出来不够优雅。
Double chineseSum = 0d;
//班级积分
Double classScore = 0d;
//定义变量
// .....
for(Student student : students){
//统计语文成绩
chineseSum += student.getChinese();
//统计班级成绩
classScore += student.getClassScore();
//统计.....
}
二、解决思路
利用顶层抽象的思维,既然要做统计,可以抽象出几个点
- 统计的属性是什么?
- 如何统计?
- 统计之后的结果放到哪里?
基于这三个维度的最终核心思想:给定任意的集合,你告诉我要统计哪些属性,如何统计,我把结果统计好放到你设定的对象里面。这样有点像Spring的控制反转,调用方只要告诉我规则就好了,统计的执行过程由统计组件进行帮你统计。调用方只需要调用过后拿结果就行了。
三、实现方案
基于上面所说的思想,再结合Java 1.8的函数式编程以及泛型和设计模式,实现了List集合的属性统计组件
核心实现类图
四、关键代码展示
通过构建统计上下文进行统计,通过函数式编程的方法指定统计属性、统计规则、统计结果放到哪里
/**
* 统计年龄、统计分数
* @author chenfoxin
* @date: 2022/9/1 17:40
* @return AbstractConsolidationMode
* @param statResult
*/
public static StatContext<StatResult> buildStatStudentContext(StatResult statResult){
return new StatContext<>(
statResult,
//统计年龄
new StatAttribute<>(Student::getAge, new IntegerStatRule(), StatResult::setAge),
//统计分数
new StatAttribute<>(Student::getClassScore, new DoubleStatRule(NumberConstants.INT_TWO), StatResult::setScore),
//统计数学+语文成绩(组合字段)
new StatAttribute<>((Function<Student, Double>) student -> DoubleUtils.add(NumberConstants.INT_TWO,
student.getChinese(),student.getMath()), new DoubleStatRule(NumberConstants.INT_TWO),
StatResult::setMathChinese));
}
List<Student> students = new ArrayList<>();
Student stu1 = new Student(11,98D,95D,87D);
Student stu2 = new Student(12,97D,56D,78D);
//构建list
students.add(stu1);
students.add(stu2);
//创建全局对象
StatResult statResult = new StatResult();
//构建统计上下文
StatContext<StatResult> context = StatManager.buildStatStudentContext(statResult);
//进行统计
StatManager.execute(students,context);
//输出结果
log.info("统计结果:" + statResult);
感兴趣的朋友可以到我的博客上把源码拉取下来看看
基于JAVA 1.8函数式编程 泛型 设计模式抽象的通用 List统计组件: 设计模式、Java8新特性实战 - List<T> 抽象统计组件