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

  • 千萬注意共享變量的使用
  • 注意裝箱拆箱的開銷
  • 基於數據量考慮使用並行流自己的成本
  • 謹慎在並行流中使用事務
相關文章
相關標籤/搜索