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

 更新时间:2021年2月25日 00:00  点击:1960

业务中需要将一组数据分类后收集总和,原本可以使用Collectors.summingInt(),但是我们的数据源是BigDecimal类型的,而Java8原生只提供了summingInt、summingLong、summingDouble三种基础类型的方法。

于是就自己动手丰衣足食吧。。

自定义工具类

public class MyCollectors {
  private MyCollectors() {
  }
//  public static <T> Collector<T, ?, BigDecimal> summingBigDecimal(Function<? super T, BigDecimal> mapper) {}
 	// BigDecimal 类型的集合求和
  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.applyAsInt(t)),
        (a, b) -> {
          a[0] = a[0].add(b[0]);
          return a;
        },
        a -> a[0],
        Collections.emptySet()
    );
  }
  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;
    // 空Set
    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;
    }
  }
  @SuppressWarnings("unchecked")
  private static <I, R> Function<I, R> castingIdentity() {
    return i -> (R) i;
  }
}

自定义函数式接口

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

测试入口

public class AnswerApp {
 public static void main(String[] args) {
    List<BigDecimal> list = Lists.newArrayList();
    for (int i = 0; i < 24; i++) {
      list.add(BigDecimal.valueOf(i + 10.2121543));
    }
    // 方式1
    BigDecimal sum = list.stream().collect(MyCollectors.summingBigDecimal(e -> e));
    System.out.println(sum.doubleValue());
    // 方式2
    Optional<BigDecimal> reduce = list.stream().reduce(BigDecimal::add);
    System.out.println(reduce.orElse(BigDecimal.valueOf(0)));
 }    
}
// OUTPUT: 521.0917032

补充:Collectors扩展接口 实现BigDecimal的相加

第一步

创建ToBigDecimalFunction接口

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

第二步

创建工具类 实现接口

import java.math.BigDecimal;
import java.util.Collections;
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 final Set<Collector.Characteristics> CH_NOID = Collections.emptySet();
  private CollectorsUtil() {
  }
  @SuppressWarnings("unchecked")
  private static <I, R> Function<I, R> castingIdentity() {
    return i -> (R) i;
  }
  /**
   * Simple implementation class for {@code Collector}.
   *
   * @param <T>
   *      the type of elements to be collected
   * @param <R>
   *      the type of the result
   */
  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[1], (a, t) -> {
      if (a[0] == null) {
        a[0] = BigDecimal.ZERO;
      }
      a[0] = a[0].add(mapper.applyAsBigDecimal(t));
    }, (a, b) -> {
      a[0] = a[0].add(b[0]);
      return a;
    }, a -> a[0], CH_NOID);
  }
}

使用测试

import com.example.javademo.JavaDemoApplicationTests;
import com.example.javademo.pojo.Student;
import com.example.javademo.utils.DataUtils;
import org.junit.Test;
import java.math.BigDecimal;
import java.util.stream.Collectors;
public class TestBigDecimal extends JavaDemoApplicationTests {
  @Test
  public void testGroupByAfterBigdecimal(){
    /*
    自定义实现对分组后的集合,属性为bigdecmal进行相加
     */
    System.out.println(DataUtils.getData().stream().collect(Collectors.groupingBy(Student::getSchool,CollectorsUtil.summingBigDecimal(Student::getMoney))));
    //归约造作
    BigDecimal reduce = DataUtils.getData().stream().map(Student::getMoney).reduce(BigDecimal.ZERO, BigDecimal::add);
    System.out.println(reduce);
    int sum = DataUtils.getData().stream().mapToInt(Student::getAge).sum();
    System.out.println(sum);
  }
}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持猪先飞。如有错误或未考虑完全的地方,望不吝赐教。

[!--infotagslink--]

相关文章

  • Java8 实现stream将对象集合list中抽取属性集合转化为map或list

    这篇文章主要介绍了Java8 实现stream将对象集合list中抽取属性集合转化为map或list的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-05
  • java8如何用Stream查List对象某属性是否有重复

    这篇文章主要介绍了java8如何用Stream查List对象某属性是否有重复的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-09-11
  • java8中的Collectors.groupingBy用法详解

    这篇文章主要介绍了java8中的Collectors.groupingBy用法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-03-17
  • Java8处理List的双层循环问题

    这篇文章主要介绍了Java8处理List的双层循环问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-19
  • 浅谈Java8 的foreach跳出循环break/return

    这篇文章主要介绍了Java8 的foreach跳出循环break/return,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-07-28
  • C语言中求和、计算平均值、方差和标准差的实例

    这篇文章主要介绍了C语言中求和、计算平均值、方差和标准差的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-12-10
  • Java 8 Stream 的终极技巧——Collectors 功能与操作方法详解

    这篇文章主要介绍了Java 8 Stream Collectors 功能与操作方法,结合实例形式详细分析了Java 8 Stream Collectors 功能、操作方法及相关注意事项,需要的朋友可以参考下...2020-05-20
  • Java8 使用流抽取List<T>集合中T的某个属性操作

    这篇文章主要介绍了Java8 使用流抽取List<T>集合中T的某个属性操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-05
  • java8时间 yyyyMMddHHmmss格式转为日期的代码

    这篇文章主要介绍了java8时间 yyyyMMddHHmmss格式转为日期的代码,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-09-17
  • Java8之Stream流代替For循环操作

    这篇文章主要介绍了Java8之Stream流代替For循环操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-19
  • Java8 自定义CompletableFuture的原理解析

    这篇文章主要介绍了Java8 自定义CompletableFuture的原理解析,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-11-04
  • Java8中Stream的一些神操作

    Stream是Java8中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作,这篇文章主要给大家介绍了Java8中Stream的一些神操作,需要的朋友可以参考下...2021-11-02
  • java8 streamList转换使用详解

    这篇文章主要介绍了java8 streamList转换使用详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-16
  • Java8通过Function获取字段名的方法(获取实体类的字段名称)

    Java8通过Function获取字段名。不用再硬编码,效果类似于mybatis-plus的LambdaQueryWrapper,对Java8通过Function获取字段名相关知识感兴趣的朋友一起看看吧...2021-09-29
  • java8 实现提取集合对象的每个属性

    这篇文章主要介绍了java8 实现提取集合对象的每个属性方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-05
  • JAVA8妙用Optional解决判断Null为空的问题方法

    本文主要介绍了JAVA8妙用Optional解决判断Null为空的问题方法,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-10-22
  • Java8优雅的字符串拼接工具类StringJoiner实例代码

    这篇文章主要给大家介绍了关于Java8优雅的字符串拼接工具类StringJoiner的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-28
  • 一元多项式加法运算

    今天小编就为大家分享一篇关于一元多项式加法运算,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧...2020-04-25
  • java8新特性 获取list某一列的操作

    这篇文章主要介绍了java8新特性 获取list某一列的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-05
  • C语言求矩阵的各列元素之和的代码示例

    这篇文章主要介绍了C语言求矩阵的各列元素之和的代码示例,这也是经常作为竞赛和计算机专业考试的基础练习出现的题目,需要的朋友可以参考下...2020-04-25