Java里如何优雅的合计多列
相信开发朋友们都有碰到一个list对象需要对其中的多列进行不同维度的计算统计,最后返回成一条数据。
以往的做法可能是对这个list对象进行循环,在循环外层定义对象和几个变量接收计算然后set到对象里面。又或者是使用stream流的sum方法计算成一个个值set到对象里。
今天介绍两种方式
方式1:stream流的reduce方法
package com.example.demo.entity;
import cn.hutool.core.util.NumberUtil;
import com.example.demo.annotation.Sum;
import com.example.demo.util.PolymerizationUtil;
import com.google.common.collect.Lists;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
import java.util.List;
/**
* @author tangsen
* @since 2023/12/29 14:27
**/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Compute {
@Sum
private BigDecimal fee;
@Sum
private Integer count;
/**
* 初始化一个空对象方便累加
*/
public static final Compute EMPTY = new Compute(new BigDecimal("0"),0);
/**
* 计算 其他类型自己拓展
* @param compute1 对象1
* @param compute2 对象2
* @return 合计对象
*/
public static Compute sum(Compute compute1,Compute compute2){
EMPTY.setFee(NumberUtil.add(compute1.getFee(),compute2.getFee()));
EMPTY.setCount(compute1.getCount() + compute2.getCount());
return EMPTY;
}
public static List<Compute> getList(){
List<Compute> computeList = Lists.newArrayList();
Compute compute1 = new Compute(new BigDecimal("11.11"),1);
Compute compute2 = new Compute(new BigDecimal("22.22"),2);
Compute compute3 = new Compute(new BigDecimal("33.33"),3);
computeList.add(compute1); computeList.add(compute2); computeList.add(compute3);
return computeList;
}
public static void main(String[] args) {
List<Compute> computeList = getList();
Compute reduce = computeList.stream().reduce(Compute.EMPTY, Compute::sum);
System.out.println(reduce);
}
}
执行结果
方式2:使用注解+反射
自定义注解
package com.example.demo.annotation;
import java.lang.annotation.*;
/**
* @author tangsen
* @date 2023/4/21 13:54
**/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Sum {
}
计算的工具类方法
package com.example.demo.util;
import cn.hutool.core.util.NumberUtil;
import com.example.demo.annotation.Sum;
import com.example.demo.entity.DemoDto;
import com.google.common.collect.Maps;
import lombok.SneakyThrows;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* @author tangsen
* @date 2023/4/21 11:27
**/
public class PolymerizationUtil{
@SneakyThrows
public static <T> T sum(List<T> list,Class<T> clazz){
T firstObject = list.get(0);
T result = clazz.newInstance();
Field[] fields = firstObject.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(Sum.class)) {
field.setAccessible(true);
Object fieldValue = list.stream()
.map(obj -> {
try {
return field.get(obj);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
})
.filter(Objects::nonNull)
.reduce((Object a, Object b) -> {
if (a instanceof Integer) {
return (Integer) a + (Integer) b;
} else if (a instanceof BigDecimal) {
return (NumberUtil.add((BigDecimal) a,(BigDecimal) b));
}else if (a instanceof String) {
return (NumberUtil.add(new BigDecimal(a.toString()),new BigDecimal(b.toString()))).toString();
} else {
return 0;
}
}).get();
field.set(result, fieldValue);
}
}
return result;
}
}
运行结果 注意实体类上需要计算的字段加注解
public static void main(String[] args) {
List<Compute> computeList = getList();
Compute compute = PolymerizationUtil.sum(computeList, Compute.class);
System.out.println(compute);
}
这里只做了合计的处理,需要拓展,可以在注解里面加属性,来定义是加减乘除