如何对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;
    }
  }
相关推荐
自在如风。2 分钟前
Java 设计模式:观察者模式详解
java·观察者模式·设计模式
Reggie_L7 分钟前
网络初识 - Java
java·网络
qq_3659116015 分钟前
WPF 五子棋项目文档
开发语言
LCY13328 分钟前
docker 常用指令整理
java·后端·spring
烟沙九洲36 分钟前
MyBatis-Plus 的 FieldStrategy 属性
java·mybatis
贝恩聊架构1 小时前
LangChain4j实战-Java AI应用开源框架之LangChain4j和Spring AI
java
跟着汪老师学编程1 小时前
44、Spring Boot 详细讲义(一)
java·spring boot·后端
ℳ₯㎕ddzོꦿ࿐1 小时前
Spring Boot 中集成 Knife4j:解决文件上传不显示文件域的问题
java·spring boot·spring