Java8利用stream对list集合中的bigdecimal进行分组求和,均值,最大值,最小值

Java8原生只提供了summingInt、summingLong、summingDouble三种基础类型的方法,想要对BigDecimal类型的数据操作需要自己新建工具类如下:

新建接口ToBigDecimalFunction

@FunctionalInterface
public interface ToBigDecimalFunction<T> {
    BigDecimal applyAsBigDecimal(T value);
}

新建工具类CollectorsUtil

public class CollectorsUtil {
    static final Set<Collector.Characteristics> CH_NOID = Collections.emptySet();

    private CollectorsUtil() {
    }

    @SuppressWarnings("unchecked")
    private static <I, R> Function<I, R> castingIdentity() {
        return i -> (R) i;
    }

    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> supplier, BiConsumer<A, T> accumulator, BinaryOperator<A> combiner,
                      Function<A, R> finisher, Set<Characteristics> characteristics) {
            this.supplier = supplier;
            this.accumulator = accumulator;
            this.combiner = combiner;
            this.finisher = finisher;
            this.characteristics = characteristics;
        }

        CollectorImpl(Supplier<A> supplier, BiConsumer<A, T> accumulator, BinaryOperator<A> combiner,
                      Set<Characteristics> characteristics) {
            this(supplier, accumulator, combiner, castingIdentity(), characteristics);
        }

        @Override
        public BiConsumer<A, T> accumulator() {
            return accumulator;
        }

        @Override
        public Supplier<A> supplier() {
            return supplier;
        }

        @Override
        public BinaryOperator<A> combiner() {
            return combiner;
        }

        @Override
        public Function<A, R> finisher() {
            return finisher;
        }

        @Override
        public Set<Characteristics> characteristics() {
            return characteristics;
        }
    }

    //求和方法
    public static <T> Collector<T, ?, BigDecimal> summingBigDecimal(ToBigDecimalFunction<? super T> mapper) {
        return new CollectorImpl<>(
                () -> new BigDecimal[]{BigDecimal.ZERO},
                (a, t) -> { a[0] = a[0].add(mapper.applyAsBigDecimal(t)); },
                (a, b) -> { a[0] = a[0].add(b[0]) ; return a; },
                a -> a[0], CH_NOID);
    }

    //求最大值
    public static <T> Collector<T, ?, BigDecimal> maxBy(ToBigDecimalFunction<? super T> mapper) {
        return new CollectorImpl<>(
                () -> new BigDecimal[]{new BigDecimal(Long.MIN_VALUE)},
                (a, t) -> { a[0] = a[0].max(mapper.applyAsBigDecimal(t)); },
                (a, b) -> { a[0] = a[0].max(b[0]) ; return a; },
                a -> a[0], CH_NOID);
    }

    //求最小值
    public static <T> Collector<T, ?, BigDecimal> minBy(ToBigDecimalFunction<? super T> mapper) {
        return new CollectorImpl<>(
                () -> new BigDecimal[]{new BigDecimal(Long.MAX_VALUE)},
                (a, t) -> { a[0] = a[0].min(mapper.applyAsBigDecimal(t)); },
                (a, b) -> { a[0] = a[0].min(b[0]) ; return a; },
                a -> a[0], CH_NOID);
    }

    //求平均值
    public static <T> Collector<T, ?, BigDecimal> averagingBigDecimal(ToBigDecimalFunction<? super T> mapper, int newScale, int roundingMode) {
        return new CollectorImpl<>(
                () -> new BigDecimal[]{BigDecimal.ZERO,BigDecimal.ZERO},
                (a, t) -> { a[0] = a[0].add(mapper.applyAsBigDecimal(t)); a[1] = a[1].add(BigDecimal.ONE); },
                (a, b) -> { a[0] = a[0].add(b[0]) ; return a; },
                a -> a[0].divide(a[1],BigDecimal.ROUND_HALF_UP).setScale(newScale, roundingMode), CH_NOID);
    }
}

新建实体类Person

@Data
class Person{
    private String sex;
    private Integer age;
    private BigDecimal score;

    public Person(String sex, Integer age, BigDecimal score) {
        this.sex = sex;
        this.age = age;
        this.score = score;
    }
}

测试用例

List<Person> list = new ArrayList<>();
list.add(new Person("男",18,new BigDecimal(100)));
list.add(new Person("男",19,new BigDecimal(90)));
list.add(new Person("女",20,new BigDecimal(80)));
list.add(new Person("女",20,new BigDecimal(70)));
list.add(new Person("女",20,null));

开始测试

//单条件筛选
//按照性别分组求分数总和
Map<String, BigDecimal> scoreCount = list.stream()
        .filter(t -> t.getScore() != null)
        .collect(Collectors.groupingBy(Person::getSex, CollectorsUtil.summingBigDecimal(Person::getScore)));
System.out.println("----按照性别分组求分数总和----");
scoreCount.forEach((k,v) -> System.out.println("key: " + k + " , " + "value: " + v));

//按照性别求分数平均值
Map<String, BigDecimal> scoreAvg = list.stream()
        .filter(t -> t.getScore() != null)
        .collect(Collectors.groupingBy(Person::getSex, CollectorsUtil.averagingBigDecimal(Person::getScore,2)));
System.out.println("----按照性别求分数平均值----");
scoreAvg.forEach((k,v) -> System.out.println("key: " + k + " , " + "value: " + v));


//多条件筛选
//多条件筛选分组属性
private static String fetchGroupKey(Person p) {
    return p.getAge() + "#" + p.getSex();
}

//按照性别年龄分组求分数总和
Map<String, BigDecimal> ageScoreCount = list.stream()
        .filter(t -> t.getScore() != null)
        .collect(Collectors.groupingBy(p -> fetchGroupKey(p), CollectorsUtil.summingBigDecimal(Person::getScore)));
System.out.println("----按照性别年龄分组求分数总和----");
ageScoreCount.forEach((k,v) -> System.out.println("key: " + k + " , " + "value: " + v));

//按照性别年龄分组求分数平均值
Map<String, BigDecimal> ageScoreAvg = list.stream()
        .filter(t -> t.getScore() != null)
        .collect(Collectors.groupingBy(p -> fetchGroupKey(p), CollectorsUtil.averagingBigDecimal(Person::getScore, 2)));
System.out.println("----按照性别年龄分组求分数平均值----");
ageScoreAvg.forEach((k,v) -> System.out.println("key: " + k + " , " + "value: " + v));

输出结果为

----按照性别分组求分数总和----
key:, value: 150
key:, value: 190
----按照性别求分数平均值----
key:, value: 75.00
key:, value: 95.00
----按照性别年龄分组求分数总和----
key: 20#女 , value: 150
key: 19#男 , value: 90
key: 18#男 , value: 100
----按照性别年龄分组求分数平均值----
key: 20#女 , value: 75.00
key: 19#男 , value: 90.00
key: 18#男 , value: 100.00

参考自:
https://blog.csdn.net/wohennis1/article/details/103834296
https://mp.weixin.qq.com/s/bd5tuRaF4dCnHHNKBCcAkQ

你可能感兴趣的:(笔记,java)