如何对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;
    }
  }
相关推荐
古法安卓4 小时前
Android-日志系统源码解析
android·java·android studio
小夏coding5 小时前
从"一把梭"到"精妙拆解" —— 滑动窗口计时框架的设计演进
java·后端
MacroZheng6 小时前
同事问我:"Claude Code经常失忆,不怕它把项目搞炸?",我:"怕,三个Markdown文件给它装个永不丢失的外置大脑!"
java·人工智能·后端
十年Java程序媛7 小时前
深度实战:JDK21 虚拟线程 + HikariCP 生产正确配比、坑点、监控全套
java·spring boot
xiaoqiMikko7 小时前
有人在搜一个不存在的 Tomcat 版本
java·tomcat
用户31268748772011 小时前
ConcurrentHashMap 怎么保证线程安全?从分段锁到 CAS+synchronized
java
vipxieliang11 小时前
ValidX vs Apache Commons Validator:功能与性能对比
java·spring boot
SimonKing11 小时前
升级Spring Boot 4后,从 Jackson 2 到 3,到底有哪些变化
java·后端·程序员
吃饱了得干活12 小时前
一篇讲清楚Spring Boot:自动装配、启动器、过滤器、拦截器、设计模式
java·spring boot·后端
lhldsg13 小时前
AI零售系统实战指南:从架构设计到落地部署全解析
java·人工智能·小程序·uni-app·零售