1、问题
最近在做报表统计相关的任务,中间涉及到很多的地方,需要同时使用SQL进行数据汇总或者在内存进行数据汇总,在内存汇总的时候,遇到一个场景,就是对Java对象数组多个属性值进行汇总。
最后认为方法三使用反射进行处理要通用一点。
2、解决方案
2.1 基于stream流
java
private static BigDecimal calculate(List<Student> studentList, Function<Student,BigDecimal> function){
return studentList.stream().map(student -> function.apply(student)).reduce(BigDecimal.ZERO,
BigDecimal::add);
}
每个字段都需要调用方法:
calculate(studentList,Student::getChinese)
但是这个方法需要调用很多次,而且和对象强相关。
2.2 基于stream流
也可用定义一个数组,一起处理。
java
BigDecimal[] reduce = studentList.stream().map(student -> new BigDecimal[]{student.getChinese(), student.getMath(), student.getEnglish()})
.reduce(new BigDecimal[]{BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO}, (a, b) -> {
for (int i = 0; i < a.length; i++) {
b[i] = b[i].add(a[i]);
}
return b;
});
2.3 基于反射
以下方法针对Long、Integer和BigDecimal的字段都进行处理:
java
* 计算列表汇总值
* @param list 输入
* @param tClass 输出类
* @return 汇总结果
* @param <T> 泛型
* @throws Exception 异常
*/
public static <T> T calculateListSum(List<T> list, Class<T> tClass) {
try {
T sumObject = tClass.getConstructor().newInstance();
Field[] declaredFields = tClass.getDeclaredFields();
Map<Field, BigDecimal> map = new HashMap<>();
for (Field field : declaredFields) {
if (field.getType().equals(Long.class) || field.getType().equals(Integer.class) || field.getType().equals(BigDecimal.class)) {
field.setAccessible(true);
map.put(field, BigDecimal.ZERO.setScale(2, RoundingMode.HALF_DOWN));
}
}
Set<Map.Entry<Field, BigDecimal>> entries = map.entrySet();
for (T t : list) {
for (Map.Entry<Field, BigDecimal> entry : entries) {
if (entry.getValue() != null && entry.getKey().get(t) != null) {
try {
BigDecimal curValue = BigDecimal.ZERO;
boolean numeric = isNumeric(String.valueOf(entry.getKey().get(t)));
if (numeric) {
if (entry.getKey().getType().equals(Long.class)) {
curValue = new BigDecimal((Long) entry.getKey().get(t));
} else if (entry.getKey().getType().equals(Integer.class)) {
curValue = new BigDecimal((Integer) entry.getKey().get(t));
} else if (entry.getKey().getType().equals(BigDecimal.class)) {
curValue = (BigDecimal) entry.getKey().get(t);
}
}
entry.setValue(entry.getValue().add(curValue));
}catch (Exception e) {
log.info("不支持的字段类型及值,字段={}",entry.getKey().getName());
}
}
}
}
Map<String, BigDecimal> resultMap = new HashMap<>();
map.forEach((key, value) -> resultMap.put(key.getName(), value));
map.keySet().forEach(field -> ReflectUtil.setFieldValue(sumObject, field, resultMap.get(field.getName())));
return sumObject;
}catch (Exception e) {
log.error("累加计算保存",e);
return null;
}
}