如何对Java对象数组多个属性值进行汇总

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;
    }
  }
相关推荐
Flynn Liang2 分钟前
Spring AI 2.0 深度解析:ChatClient、Advisor 链与 MCP——Java 工程师的 AI 落地最优解
java·人工智能·spring·大模型·架构设计·spring ai
灿飞8 分钟前
Kotlin与Java虚拟机六:基础与类型系统:一切皆对象,但对象有代价
java·kotlin
计算机毕设定制辅导-无忧学长18 分钟前
《基于微信小程序健康习惯激励系统设计与实现》
java·spring boot·mysql·微信小程序·uniapp·健康习惯激励系统
揽星河..23 分钟前
【C语言】指针
c语言·开发语言
小小数媒成员40 分钟前
UGUI原理(一)
开发语言·游戏·unity·游戏引擎
速易达网络1 小时前
Three.js 动画入门教学:从场景搭建到流畅动效
开发语言·javascript·ecmascript
福大大架构师每日一题1 小时前
excelize v2.11.1发布:Go 1.26.0起步,16项安全修复与嵌入对象能力全面升级
开发语言·安全·golang
Sarvartha1 小时前
集合概述 & Collection 接口
开发语言
雪芽蓝域zzs1 小时前
第 1 章:IDEA 创建 SpringBoot3.5.16 Maven 项目
java·maven·intellij-idea
golang学习记1 小时前
IDEA 开始换芯,发布全新AI版终端
java·人工智能·intellij-idea