Java8中Collectors求和功能的自定义扩展

原由

业务中须要将一组数据分类后收集总和,本来能够使用Collectors.summingInt(),可是咱们的数据源是BigDecimal类型的,而Java8原生只提供了summingInt、summingLong、summingDouble三种基础类型的方法。因而就本身动手丰衣足食吧。。app

指望目标:this

Map<String, BigDecimal> result = Arrays.stream(records).parallel().collect(Collectors.groupingBy(
    Record::getType, CollectorsUtil.summingBigDecimal(Record::getAmount)));

实践

1. 依葫芦
先分析一下Collectors.summingInt()方法code

public static <T> Collector<T, ?, Integer> summingInt(ToIntFunction<? super T> mapper) {
    return new CollectorImpl<>(
        () -> new int[1],
        (a, t) -> { a[0] += mapper.applyAsInt(t); },
        (a, b) -> { a[0] += b[0]; return a; },
        a -> a[0], CH_NOID);
    }

该方法接受ToIntFunction<? super T>类型的参数,返回CollectorImpl类型的实例化对象。CollectorImplCollector接口的惟一实现类对象

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的构造器参数,可知summingInt()方法是这样的接口

arg[0]建立一个计算用的容器: () -> new int[1]
arg[1]为计算逻辑: (a, t) -> { a[0] += mapper.applyAsInt(t); }
arg[2]为合并逻辑: (a, b) -> { a[0] += b[0]; return a; }
arg[3]为返回最终计算值: a -> a[0]
arg[4]为空Set(不知道干什么用。。): Collections.emptySet()事务

2. 画瓢
很天然的,BigDecimal的就是这样了ip

public static <T> Collector<T, ?, BigDecimal> summingBigDecimal(Function<? super T, BigDecimal> mapper) {
    return new CollectorImpl<>(() -> new BigDecimal[] { BigDecimal.ZERO }, (a, t) -> {
        a[0] = a[0].add(mapper.apply(t));
    }, (a, b) -> {
        a[0] = a[0].add(b[0]);
        return a;
    }, a -> a[0], CH_NOID);
}

Java8并行流的一些tips

  • 千万注意共享变量的使用
  • 注意装箱拆箱的开销
  • 基于数据量考虑使用并行流自己的成本
  • 谨慎在并行流中使用事务
相关文章
相关标签/搜索