目录
用枚举+Lambda 优化代码
业务需求: 1、统计4个业务指标的分别按照本月,上月、去年本月的日期维度的数据 2、其中本月需要额外按照每周统计数据,最终数据以一个二维表格形式展示
大致效果如下:
原代码
private void calcBIData(List<SystemCalendar> currentMonthCalendarList,
List<ReportUserProjectBusinessIndicators> currentMonthBIList,
List<ReportUserProjectBusinessIndicators> lastMonthBIList,
List<ReportUserProjectBusinessIndicators> lastYearThisMonthBIList,
ProjectStatisticsReportResult result){
ProjectStatisticsReportByDetailResult newRequirementData = new ProjectStatisticsReportByDetailResult();
ProjectStatisticsReportByDetailResult numberOfExternalRecruitmentExpertsData = new ProjectStatisticsReportByDetailResult();
ProjectStatisticsReportByDetailResult numberOfRecommendedExpertsData = new ProjectStatisticsReportByDetailResult();
ProjectStatisticsReportByDetailResult numberOfCheckedActivitysData = new ProjectStatisticsReportByDetailResult();
Map<LocalDate,List<ReportUserProjectBusinessIndicators>> currentMonthBIMap = currentMonthBIList.stream()
.collect(Collectors.groupingBy(r->r.getDateTime().toLocalDate()));
//先计算本月的数据
int[][] currentMonthWeekData = new int[5][4];
for(int[] item:currentMonthWeekData){
Arrays.fill(item,0);
}
int[] currentMonthTotalData = new int[]{0,0,0,0};
for(SystemCalendar calendar:currentMonthCalendarList){
List<ReportUserProjectBusinessIndicators> BIList = currentMonthBIMap.get(calendar.getDate().toLocalDate());
if(CollectionUtils.isEmpty(BIList)){
continue;
}
int index = calendar.getWeekOfMonth()-1;
for(ReportUserProjectBusinessIndicators BI:BIList){
currentMonthWeekData[index][0] = currentMonthWeekData[index][0] + BI.getNumberOfCreateRequirement();
currentMonthWeekData[index][1] = currentMonthWeekData[index][1] + BI.getNumberOfExternalRecruitmentExperts();
currentMonthWeekData[index][2] = currentMonthWeekData[index][2] + BI.getNumberOfRecommendedExperts();
currentMonthWeekData[index][3] = currentMonthWeekData[index][3] + BI.getNumberOfCheckedActivitys();
currentMonthTotalData[0] = currentMonthTotalData[0] + BI.getNumberOfCreateRequirement();
currentMonthTotalData[1] = currentMonthTotalData[1] + BI.getNumberOfExternalRecruitmentExperts();
currentMonthTotalData[2] = currentMonthTotalData[2] + BI.getNumberOfRecommendedExperts();
currentMonthTotalData[3] = currentMonthTotalData[3] + BI.getNumberOfCheckedActivitys();
}
}
//计算上月的数据
int[] lastMonthTotalData = new int[]{0,0,0,0};
for(ReportUserProjectBusinessIndicators BI:lastMonthBIList){
lastMonthTotalData[0] = lastMonthTotalData[0] + BI.getNumberOfCreateRequirement();
lastMonthTotalData[1] = lastMonthTotalData[1] + BI.getNumberOfExternalRecruitmentExperts();
lastMonthTotalData[2] = lastMonthTotalData[2] + BI.getNumberOfRecommendedExperts();
lastMonthTotalData[3] = lastMonthTotalData[3] + BI.getNumberOfCheckedActivitys();
}
//计算去年的数据
int[] lastYearThisMonthData = new int[]{0,0,0,0};
for(ReportUserProjectBusinessIndicators BI:lastYearThisMonthBIList){
lastYearThisMonthData[0] = lastYearThisMonthData[0] + BI.getNumberOfCreateRequirement();
lastYearThisMonthData[1] = lastYearThisMonthData[1] + BI.getNumberOfExternalRecruitmentExperts();
lastYearThisMonthData[2] = lastYearThisMonthData[2] + BI.getNumberOfRecommendedExperts();
lastYearThisMonthData[3] = lastYearThisMonthData[3] + BI.getNumberOfCheckedActivitys();
}
//计算各业务指标的同比环比
newRequirementData.setFifthWeekDataOfCurrentMonth(new BigDecimal(currentMonthWeekData[0][0]));
newRequirementData.setSecondWeekDataOfCurrentMonth(new BigDecimal(currentMonthWeekData[1][0]));
newRequirementData.setThirdWeekDataOfCurrentMonth(new BigDecimal(currentMonthWeekData[2][0]));
newRequirementData.setFourthWeekDataOfCurrentMonth(new BigDecimal(currentMonthWeekData[3][0]));
newRequirementData.setFifthWeekDataOfCurrentMonth(new BigDecimal(currentMonthWeekData[4][0]));
newRequirementData.setTotalDataOfCurrentMonth(new BigDecimal(currentMonthTotalData[0]));
newRequirementData.setLastMonthData(new BigDecimal(lastMonthTotalData[0]));
newRequirementData.setLastYearThisMonthData(new BigDecimal(lastYearThisMonthData[0]));
newRequirementData.setMonthOnMonth(BusinessReportUtils.calcMonthOnMonth(
newRequirementData.getTotalDataOfCurrentMonth(),newRequirementData.getLastMonthData()));
newRequirementData.setYearOnYear(BusinessReportUtils.calcYearOnYear(
newRequirementData.getTotalDataOfCurrentMonth(),newRequirementData.getLastYearThisMonthData()));
numberOfExternalRecruitmentExpertsData.setFifthWeekDataOfCurrentMonth(new BigDecimal(currentMonthWeekData[0][1]));
numberOfExternalRecruitmentExpertsData.setSecondWeekDataOfCurrentMonth(new BigDecimal(currentMonthWeekData[1][1]));
numberOfExternalRecruitmentExpertsData.setThirdWeekDataOfCurrentMonth(new BigDecimal(currentMonthWeekData[2][1]));
numberOfExternalRecruitmentExpertsData.setFourthWeekDataOfCurrentMonth(new BigDecimal(currentMonthWeekData[3][1]));
numberOfExternalRecruitmentExpertsData.setFifthWeekDataOfCurrentMonth(new BigDecimal(currentMonthWeekData[4][1]));
numberOfExternalRecruitmentExpertsData.setTotalDataOfCurrentMonth(new BigDecimal(currentMonthTotalData[1]));
numberOfExternalRecruitmentExpertsData.setLastMonthData(new BigDecimal(lastMonthTotalData[1]));
numberOfExternalRecruitmentExpertsData.setLastYearThisMonthData(new BigDecimal(lastYearThisMonthData[1]));
numberOfExternalRecruitmentExpertsData.setMonthOnMonth(BusinessReportUtils.calcMonthOnMonth(
numberOfExternalRecruitmentExpertsData.getTotalDataOfCurrentMonth(),numberOfExternalRecruitmentExpertsData.getLastMonthData()));
numberOfExternalRecruitmentExpertsData.setYearOnYear(BusinessReportUtils.calcYearOnYear(
numberOfExternalRecruitmentExpertsData.getTotalDataOfCurrentMonth(),numberOfExternalRecruitmentExpertsData.getLastYearThisMonthData()));
numberOfRecommendedExpertsData.setFifthWeekDataOfCurrentMonth(new BigDecimal(currentMonthWeekData[0][2]));
numberOfRecommendedExpertsData.setSecondWeekDataOfCurrentMonth(new BigDecimal(currentMonthWeekData[1][2]));
numberOfRecommendedExpertsData.setThirdWeekDataOfCurrentMonth(new BigDecimal(currentMonthWeekData[2][2]));
numberOfRecommendedExpertsData.setFourthWeekDataOfCurrentMonth(new BigDecimal(currentMonthWeekData[3][2]));
numberOfRecommendedExpertsData.setFifthWeekDataOfCurrentMonth(new BigDecimal(currentMonthWeekData[4][2]));
numberOfRecommendedExpertsData.setTotalDataOfCurrentMonth(new BigDecimal(currentMonthTotalData[2]));
numberOfRecommendedExpertsData.setLastMonthData(new BigDecimal(lastMonthTotalData[2]));
numberOfRecommendedExpertsData.setLastYearThisMonthData(new BigDecimal(lastYearThisMonthData[2]));
numberOfRecommendedExpertsData.setMonthOnMonth(BusinessReportUtils.calcMonthOnMonth(
numberOfRecommendedExpertsData.getTotalDataOfCurrentMonth(),numberOfRecommendedExpertsData.getLastMonthData()));
numberOfRecommendedExpertsData.setYearOnYear(BusinessReportUtils.calcYearOnYear(
numberOfRecommendedExpertsData.getTotalDataOfCurrentMonth(),numberOfRecommendedExpertsData.getLastYearThisMonthData()));
numberOfCheckedActivitysData.setFifthWeekDataOfCurrentMonth(new BigDecimal(currentMonthWeekData[0][3]));
numberOfCheckedActivitysData.setSecondWeekDataOfCurrentMonth(new BigDecimal(currentMonthWeekData[1][3]));
numberOfCheckedActivitysData.setThirdWeekDataOfCurrentMonth(new BigDecimal(currentMonthWeekData[2][3]));
numberOfCheckedActivitysData.setFourthWeekDataOfCurrentMonth(new BigDecimal(currentMonthWeekData[3][3]));
numberOfCheckedActivitysData.setFifthWeekDataOfCurrentMonth(new BigDecimal(currentMonthWeekData[4][3]));
numberOfCheckedActivitysData.setTotalDataOfCurrentMonth(new BigDecimal(currentMonthTotalData[3]));
numberOfCheckedActivitysData.setLastMonthData(new BigDecimal(lastMonthTotalData[3]));
numberOfCheckedActivitysData.setLastYearThisMonthData(new BigDecimal(lastYearThisMonthData[3]));
numberOfCheckedActivitysData.setMonthOnMonth(BusinessReportUtils.calcMonthOnMonth(
numberOfCheckedActivitysData.getTotalDataOfCurrentMonth(),numberOfCheckedActivitysData.getLastMonthData()));
numberOfCheckedActivitysData.setYearOnYear(BusinessReportUtils.calcYearOnYear(
numberOfCheckedActivitysData.getTotalDataOfCurrentMonth(),numberOfCheckedActivitysData.getLastYearThisMonthData()));
//设置返回结果
result.setNewRequirementData(newRequirementData);
result.setNumberOfCheckedActivitysData(numberOfCheckedActivitysData);
result.setNumberOfExternalRecruitmentExpertsData(numberOfExternalRecruitmentExpertsData);
result.setNumberOfRecommendedExpertsData(numberOfRecommendedExpertsData);
}
原代码存在问题:
- 可读性很差,各种通过下标方式访问累加器,不方便理解代码。
- 不方便维度,如果后续需要调整日期维度或数据维度,很难修改。
优化后的代码
定义一个int类型的累加器
:
/**
* int类型累加器
*/
public class IntAccumulator {
/**
* 当前的值
*/
private int value;
/**
* 构造一个累加器
*/
public IntAccumulator(int initValue){
this.value = initValue;
}
/**
* 获取当前值
* @return int
*/
public int getValue(){
return value;
}
/**
* 累加值
* @param value
* @return void
*/
public void accumulate(Integer value){
if(value==null){
return;
}
this.value += value;
}
/**
* 累加值
* @param value
* @return void
*/
public void accumulate(int value){
this.value += value;
}
}
定义数据维度的枚举
:
在枚举里增加一个Lambda表达式,用于获取每个数据维度的数据的处理方法。
/**
* 项目统计报表的数据类型枚举
*/
private enum ProjectStatisticsReportDataType{
NEW_REQUIREMENT(ReportUserProjectBusinessIndicators::getNumberOfCreateRequirement),
NUMBER_OF_EXTERNAL_RECRUITMENT_EXPERTS(ReportUserProjectBusinessIndicators::getNumberOfExternalRecruitmentExperts),
NUMBER_OF_RECOMMENDED_EXPERTS(ReportUserProjectBusinessIndicators::getNumberOfRecommendedExperts),
NUMBER_OF_CHECKED_ACTIVITYS(ReportUserProjectBusinessIndicators::getNumberOfCheckedActivitys),
;
/**
* 构建一个项目统计报表的数据类型枚举
* @param getBIDataFun
* @return
*/
private ProjectStatisticsReportDataType(Function<ReportUserProjectBusinessIndicators,Integer> getBIDataFun){
this.getBIDataFun = getBIDataFun;
}
/**
* 获取业务数据的方法
*/
private Function<ReportUserProjectBusinessIndicators,Integer> getBIDataFun;
/**
* 获取业务数据
* @param businessIndicators
* @return java.lang.Integer
*/
private Integer getBIData(ReportUserProjectBusinessIndicators businessIndicators){
return getBIDataFun.apply(businessIndicators);
}
}
定义日期维度的枚举
:
在枚举里增加一个Lambda表达式,用于设置每个日期维度的统计结果的值。
/**
* 项目统计报表的日期类型枚举
*/
private enum ProjectStatisticsReportDateType{
CURRENT_MONT((r,v)->r.setTotalDataOfCurrentMonth(new BigDecimal(v))),
LAST_MONTH((r,v)->r.setLastMonthData(new BigDecimal(v))),
LAST_YEAR_THIS_MONTH((r,v)->r.setLastYearThisMonthData(new BigDecimal(v))),
;
/**
* 项目统计报表的日期类型枚举
* @param setDataFun
*/
private ProjectStatisticsReportDateType(
BiConsumer<ProjectStatisticsReportByDetailResult,Integer> setDataFun){
this.setDataFun = setDataFun;
}
/**
* 设置数据的方法
*/
private BiConsumer<ProjectStatisticsReportByDetailResult,Integer> setDataFun;
/**
* 设置数据
* @param result
* @param value
* @return void
*/
public void setData(ProjectStatisticsReportByDetailResult result,int value){
this.setDataFun.accept(result,value);
}
}
定义本月第几周类型的枚举
:
在枚举里增加一个Lambda表达式,用于设置每周的统计结果的值。
/**
* 项目统计报表的本月第几周类型枚举
*/
private enum ProjectStatisticsReportCurrentMonthWeek{
FIRST((r,v)->r.setFirstWeekDataOfCurrentMonth(new BigDecimal(v))),
SECOND((r,v)->r.setSecondWeekDataOfCurrentMonth(new BigDecimal(v))),
THIRD((r,v)->r.setThirdWeekDataOfCurrentMonth(new BigDecimal(v))),
FOURTH((r,v)->r.setFourthWeekDataOfCurrentMonth(new BigDecimal(v))),
FIFTH((r,v)->r.setFifthWeekDataOfCurrentMonth(new BigDecimal(v))),
;
/**
* 项目统计报表的本月第几周类型枚举
* @param setDataFun
*/
private ProjectStatisticsReportCurrentMonthWeek(
BiConsumer<ProjectStatisticsReportByDetailResult,Integer> setDataFun){
this.setDataFun = setDataFun;
}
/**
* 设置数据的方法
*/
private BiConsumer<ProjectStatisticsReportByDetailResult,Integer> setDataFun;
/**
* 设置数据
* @param result
* @param value
* @return void
*/
public void setData(ProjectStatisticsReportByDetailResult result,int value){
this.setDataFun.accept(result,value);
}
}
新的统计代码
:
private Map<ProjectStatisticsReportDataType,ProjectStatisticsReportByDetailResult> getAndCalcBIData(
List<SystemCalendar> currentMonthCalendarList,
List<ReportUserProjectBusinessIndicators> currentMonthBIList,
List<ReportUserProjectBusinessIndicators> lastMonthBIList,
List<ReportUserProjectBusinessIndicators> lastYearThisMonthBIList){
//转行日期Map
Map<LocalDate,SystemCalendar> currentMonthCalendarMap = currentMonthCalendarList.stream()
.collect(Collectors.toMap(r->r.getDate().toLocalDate(),Function.identity()));
//定义累加器
Map<ProjectStatisticsReportDateType,Map<ProjectStatisticsReportDataType, IntAccumulator>> monthAccumulatorMap
=Stream.of(ProjectStatisticsReportDateType.values())
.collect(Collectors.toMap(Function.identity(),r->getInitDataTypeAccumulatorMap()));
Map<ProjectStatisticsReportCurrentMonthWeek,Map<ProjectStatisticsReportDataType, IntAccumulator>> weekAccumulatorMap
=Stream.of(ProjectStatisticsReportCurrentMonthWeek.values())
.collect(Collectors.toMap(Function.identity(),r->getInitDataTypeAccumulatorMap()));
//定义报表明细结果
Map<ProjectStatisticsReportDataType,ProjectStatisticsReportByDetailResult> reportDetailMap
=Stream.of(ProjectStatisticsReportDataType.values())
.collect(Collectors.toMap(Function.identity(),r->new ProjectStatisticsReportByDetailResult()));
//先计算本月的数据
currentMonthBIList.forEach(r->{
SystemCalendar calendar = currentMonthCalendarMap.get(r.getDateTime().toLocalDate());
int index = calendar.getWeekOfMonth()-1;
weekAccumulatorMap.get(ProjectStatisticsReportCurrentMonthWeek.values()[index])
.forEach((k,v)->{
v.accumulate(k.getBIData(r));
});
monthAccumulatorMap.get(ProjectStatisticsReportDateType.CURRENT_MONT)
.forEach((k,v)->{
v.accumulate(k.getBIData(r));
});
});
//计算上月的数据
lastMonthBIList.forEach(r->{
monthAccumulatorMap.get(ProjectStatisticsReportDateType.LAST_MONTH)
.forEach((k,v)->{
v.accumulate(k.getBIData(r));
});
});
//计算去年的数据
lastYearThisMonthBIList.forEach(r->{
monthAccumulatorMap.get(ProjectStatisticsReportDateType.LAST_YEAR_THIS_MONTH)
.forEach((k,v)->{
v.accumulate(k.getBIData(r));
});
});
//填充数据
fillData(reportDetailMap,monthAccumulatorMap,weekAccumulatorMap);
return reportDetailMap;
}
/**
* 填充数据
* @param reportDetailMap
* @param monthAccumulatorMap
* @param weekAccumulatorMap
* @return void
*/
private void fillData(Map<ProjectStatisticsReportDataType,ProjectStatisticsReportByDetailResult> reportDetailMap,
Map<ProjectStatisticsReportDateType, Map<ProjectStatisticsReportDataType, IntAccumulator>> monthAccumulatorMap,
Map<ProjectStatisticsReportCurrentMonthWeek,Map<ProjectStatisticsReportDataType, IntAccumulator>> weekAccumulatorMap){
weekAccumulatorMap.forEach((k,v)->{
v.forEach((k2,v2)->{
k.setData(reportDetailMap.get(k2),v2.getValue());
});
});
monthAccumulatorMap.forEach((k,v)->{
v.forEach((k2,v2)->{
k.setData(reportDetailMap.get(k2),v2.getValue());
});
});
//计算同比环比
reportDetailMap.forEach((k,v)->{
v.setMonthOnMonth(BusinessReportUtils.calcMonthOnMonth(
v.getTotalDataOfCurrentMonth(),v.getLastMonthData()));
v.setYearOnYear(BusinessReportUtils.calcYearOnYear(
v.getTotalDataOfCurrentMonth(),v.getLastYearThisMonthData()));
});
}
优化说明:
- 增加了业务指标枚举,并在枚举类设置了取相应指标的方法,将同一个业务规则封装到同一块代码里,后续如果需要增加新的业务指标,只需要在枚举里增加新的枚举,同时设置取新的指标的数据的方法即可,方便了以后的扩展。
- 增加日期月维度的枚举,并在枚举类设置修改枚举对应的报表结果的数据的方法,方便了以后的扩展。
- 增加了本月第几周的枚举,并在枚举类设置修改枚举对应的报表结果的数据的方法,方便了以后的扩展。
- 通过构造以上3个枚举之后,实际的报表数据统计代码就不用再考虑具体的业务指标规则了,只需要写好统计的代码,并调用不同枚举的方法即可,将业务的统计代码和实际的业务指标数据隔离。即实现了方法和数据的分离。
- 最终效果可读性和可维护性大大提升。
版权声明:本文为weixin_48990070原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。