如何对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;
    }
  }
相关推荐
叫致寒吧1 小时前
Tomcat详解
java·tomcat
同学小张2 小时前
【端侧AI 与 C++】1. llama.cpp源码编译与本地运行
开发语言·c++·aigc·llama·agi·ai-native
踢球的打工仔3 小时前
PHP面向对象(7)
android·开发语言·php
S***26755 小时前
基于SpringBoot和Leaflet的行政区划地图掩膜效果实战
java·spring boot·后端
汤姆yu5 小时前
基于python的外卖配送及数据分析系统
开发语言·python·外卖分析
Yue丶越5 小时前
【C语言】字符函数和字符串函数
c语言·开发语言·算法
马剑威(威哥爱编程)6 小时前
鸿蒙6开发视频播放器的屏幕方向适配问题
java·音视频·harmonyos
JIngJaneIL6 小时前
社区互助|社区交易|基于springboot+vue的社区互助交易系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·论文·毕设·社区互助
翔云 OCR API6 小时前
人脸识别API开发者对接代码示例
开发语言·人工智能·python·计算机视觉·ocr
V***u4536 小时前
MS SQL Server partition by 函数实战二 编排考场人员
java·服务器·开发语言