Java8 Stream 自定义 Collector 通过 list 生成合计对象

前言

  • 项目中经常遇到查询一个列表在最下面显示合计项的情况
  • 本着后端能做就后端全做的原则合并项的计算就后端完成吧
  • 本工具类定义为 仅合并待合并类的 BigDecimal 属性 其他属性合并可参考代码自行实现

Collector 工具代码

注: 代码参考 java.util.stream.summingInt 实现

package com.**.**.util;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;

/**
 * 集合计算工具
 */
public class CollectorsUtil {

    static class CollectorImpl<T, A, R> implements Collector<T, A, R> {
        private final Supplier<A> supplier;
        private final BiConsumer<A, T> accumulator;
        private final BinaryOperator<A> combiner;
        private final Function<A, R> finisher;
        private final Set<Characteristics> characteristics;

        CollectorImpl(Supplier<A> var1, BiConsumer<A, T> var2, BinaryOperator<A> var3, Function<A, R> var4) {
            this.supplier = var1;
            this.accumulator = var2;
            this.combiner = var3;
            this.finisher = var4;
            this.characteristics = Collections.emptySet();
        }

        public BiConsumer<A, T> accumulator() {
            return this.accumulator;
        }

        public Supplier<A> supplier() {
            return this.supplier;
        }

        public BinaryOperator<A> combiner() {
            return this.combiner;
        }

        public Function<A, R> finisher() {
            return this.finisher;
        }

        public Set<Collector.Characteristics> characteristics() {
            return this.characteristics;
        }
    }

    /**
     * 合并对象中的BigDecimal属性
     *
     * @param clazz 待返回的对象clazz
     * @param <T>   待返回的类泛型
     * @return 合并后的结果
     */
    public static <T> Collector<T, ?, T> summingBigDecimal(Class<T> clazz) {
        List<Field> fieldBigDecimalList = new ArrayList<>();
        Field[] fieldsAll = clazz.getDeclaredFields();
        for (Field field : fieldsAll) {
            if ("class java.math.BigDecimal".equals(field.getGenericType().toString())) {
                fieldBigDecimalList.add(field);
            }
        }

        return new CollectorImpl(() -> {
            try {
                return clazz.newInstance();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }, (oldOne, newOne) -> {
            combiner(fieldBigDecimalList, oldOne, newOne);
        }, (var0x, var1) -> {
            combiner(fieldBigDecimalList, var0x, var1);
            return var0x;
        }, (var0x) -> var0x);
    }

    /**
     * 合并两个对象 并设置到第一个对象中
     */
    private static void combiner(List<Field> fieldBigDecimalList, Object var0, Object var1) {
        try {
            for (Field thisField : fieldBigDecimalList) {
                thisField.setAccessible(true);
                Object thisFieldObj = thisField.get(var1);

                BigDecimal newOneBigDecimalField = BigDecimal.ZERO;
                if (thisFieldObj != null) {
                    newOneBigDecimalField = (BigDecimal) thisFieldObj;
                }

                Object oldFieldObj = thisField.get(var0);

                BigDecimal oldOneBigDecimalField = BigDecimal.ZERO;
                if (oldFieldObj != null) {
                    oldOneBigDecimalField = (BigDecimal) oldFieldObj;
                }

                thisField.set(var0, oldOneBigDecimalField.add(newOneBigDecimalField));
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}

测试

  • 测试代码
package com.**.**;

import com.alibaba.fastjson.JSON;
import com.**.**.util.CollectorsUtil;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

/**
 * CollectorTest
 */
public class CollectorTest {

    public static void main(String[] args) {

        List<Data> list = new ArrayList<>();
        list.add(new Data("2022-08-01", new BigDecimal(1), new BigDecimal("1.1")));
        list.add(new Data("2022-08-02", new BigDecimal(2), new BigDecimal("1.2")));
        list.add(new Data("2022-08-03", new BigDecimal(3), new BigDecimal("1.3")));

        DataCount count = list.stream().collect(CollectorsUtil.summingBigDecimal(DataCount.class));

        for (Data data : list) {
            System.out.println("data: " + JSON.toJSONString(data));
        }
        System.out.println("count: " + JSON.toJSONString(count));
    }

    public static class Data extends DataCount {
        private String dateStr;

        /**
         * 必须有无参构造
         */
        public Data() {
        }

        public Data(String dateStr, BigDecimal num, BigDecimal money) {
            super(num, money);
            this.dateStr = dateStr;
        }

        public String getDateStr() {
            return dateStr;
        }

        public void setDateStr(String dateStr) {
            this.dateStr = dateStr;
        }
    }

    public static class DataCount {
        private BigDecimal num;
        private BigDecimal money;

        /**
         * 必须有无参构造
         */
        public DataCount() {
        }

        public DataCount(BigDecimal num, BigDecimal money) {
            this.num = num;
            this.money = money;
        }

        public BigDecimal getNum() {
            return num;
        }

        public void setNum(BigDecimal num) {
            this.num = num;
        }

        public BigDecimal getMoney() {
            return money;
        }

        public void setMoney(BigDecimal money) {
            this.money = money;
        }
    }
}
  • 输出结果
data: {"dateStr":"2022-08-01","money":1.1,"num":1}
data: {"dateStr":"2022-08-02","money":1.2,"num":2}
data: {"dateStr":"2022-08-03","money":1.3,"num":3}
count: {"money":3.6,"num":6}
posted @ 2022-08-11 10:14  Heei  阅读(514)  评论(0编辑  收藏  举报