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}