对BigDecimal类型进行分组聚合

参考:
https://blog.csdn.net/weixin_44905182/article/details/105792291
https://www.jianshu.com/p/b906355858f3

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

新建接口ToBigDecimalFunction

  1. @FunctionalInterface
  2. public interface ToBigDecimalFunction<T> {
  3. BigDecimal applyAsBigDecimal(T value);
  4. }

新建工具类CollectorsUtil

  1. public class CollectorsUtil {
  2. static final Set<Collector.Characteristics> CH_NOID = Collections.emptySet();
  3. private CollectorsUtil() {
  4. }
  5. @SuppressWarnings("unchecked")
  6. private static <I, R> Function<I, R> castingIdentity() {
  7. return i -> (R) i;
  8. }
  9. static class CollectorImpl<T, A, R> implements Collector<T, A, R> {
  10. private final Supplier<A> supplier;
  11. private final BiConsumer<A, T> accumulator;
  12. private final BinaryOperator<A> combiner;
  13. private final Function<A, R> finisher;
  14. private final Set<Characteristics> characteristics;
  15. CollectorImpl(Supplier<A> supplier, BiConsumer<A, T> accumulator, BinaryOperator<A> combiner,
  16. Function<A, R> finisher, Set<Characteristics> characteristics) {
  17. this.supplier = supplier;
  18. this.accumulator = accumulator;
  19. this.combiner = combiner;
  20. this.finisher = finisher;
  21. this.characteristics = characteristics;
  22. }
  23. CollectorImpl(Supplier<A> supplier, BiConsumer<A, T> accumulator, BinaryOperator<A> combiner,
  24. Set<Characteristics> characteristics) {
  25. this(supplier, accumulator, combiner, castingIdentity(), characteristics);
  26. }
  27. @Override
  28. public BiConsumer<A, T> accumulator() {
  29. return accumulator;
  30. }
  31. @Override
  32. public Supplier<A> supplier() {
  33. return supplier;
  34. }
  35. @Override
  36. public BinaryOperator<A> combiner() {
  37. return combiner;
  38. }
  39. @Override
  40. public Function<A, R> finisher() {
  41. return finisher;
  42. }
  43. @Override
  44. public Set<Characteristics> characteristics() {
  45. return characteristics;
  46. }
  47. }
  48. //求和方法
  49. public static <T> Collector<T, ?, BigDecimal> summingBigDecimal(ToBigDecimalFunction<? super T> mapper) {
  50. return new CollectorImpl<>(
  51. () -> new BigDecimal[]{BigDecimal.ZERO},
  52. (a, t) -> { a[0] = a[0].add(mapper.applyAsBigDecimal(t)); },
  53. (a, b) -> { a[0] = a[0].add(b[0]) ; return a; },
  54. a -> a[0], CH_NOID);
  55. }
  56. //求最大值
  57. public static <T> Collector<T, ?, BigDecimal> maxBy(ToBigDecimalFunction<? super T> mapper) {
  58. return new CollectorImpl<>(
  59. () -> new BigDecimal[]{new BigDecimal(Long.MIN_VALUE)},
  60. (a, t) -> { a[0] = a[0].max(mapper.applyAsBigDecimal(t)); },
  61. (a, b) -> { a[0] = a[0].max(b[0]) ; return a; },
  62. a -> a[0], CH_NOID);
  63. }
  64. //求最小值
  65. public static <T> Collector<T, ?, BigDecimal> minBy(ToBigDecimalFunction<? super T> mapper) {
  66. return new CollectorImpl<>(
  67. () -> new BigDecimal[]{new BigDecimal(Long.MAX_VALUE)},
  68. (a, t) -> { a[0] = a[0].min(mapper.applyAsBigDecimal(t)); },
  69. (a, b) -> { a[0] = a[0].min(b[0]) ; return a; },
  70. a -> a[0], CH_NOID);
  71. }
  72. //求平均值
  73. public static <T> Collector<T, ?, BigDecimal> averagingBigDecimal(ToBigDecimalFunction<? super T> mapper, int newScale, int roundingMode) {
  74. return new CollectorImpl<>(
  75. () -> new BigDecimal[]{BigDecimal.ZERO,BigDecimal.ZERO},
  76. (a, t) -> { a[0] = a[0].add(mapper.applyAsBigDecimal(t)); a[1] = a[1].add(BigDecimal.ONE); },
  77. (a, b) -> { a[0] = a[0].add(b[0]) ; return a; },
  78. a -> a[0].divide(a[1],BigDecimal.ROUND_HALF_UP).setScale(newScale, roundingMode), CH_NOID);
  79. }
  80. }

使用示例:

  1. //单条件筛选
  2. //按照性别分组求分数总和
  3. Map<String, BigDecimal> scoreCount = list.stream()
  4. .filter(t -> t.getScore() != null)
  5. .collect(Collectors.groupingBy(Person::getSex, CollectorsUtil.summingBigDecimal(Person::getScore)));
  6. System.out.println("----按照性别分组求分数总和----");
  7. scoreCount.forEach((k,v) -> System.out.println("key: " + k + " , " + "value: " + v));
  8. //按照性别求分数平均值
  9. Map<String, BigDecimal> scoreAvg = list.stream()
  10. .filter(t -> t.getScore() != null)
  11. .collect(Collectors.groupingBy(Person::getSex, CollectorsUtil.averagingBigDecimal(Person::getScore,2)));
  12. System.out.println("----按照性别求分数平均值----");
  13. scoreAvg.forEach((k,v) -> System.out.println("key: " + k + " , " + "value: " + v));
  14. //多条件筛选
  15. //多条件筛选分组属性
  16. private static String fetchGroupKey(Person p) {
  17. return p.getAge() + "#" + p.getSex();
  18. }
  19. //按照性别年龄分组求分数总和
  20. Map<String, BigDecimal> ageScoreCount = list.stream()
  21. .filter(t -> t.getScore() != null)
  22. .collect(Collectors.groupingBy(p -> fetchGroupKey(p), CollectorsUtil.summingBigDecimal(Person::getScore)));
  23. System.out.println("----按照性别年龄分组求分数总和----");
  24. ageScoreCount.forEach((k,v) -> System.out.println("key: " + k + " , " + "value: " + v));
  25. //按照性别年龄分组求分数平均值
  26. Map<String, BigDecimal> ageScoreAvg = list.stream()
  27. .filter(t -> t.getScore() != null)
  28. .collect(Collectors.groupingBy(p -> fetchGroupKey(p), CollectorsUtil.averagingBigDecimal(Person::getScore, 2)));
  29. System.out.println("----按照性别年龄分组求分数平均值----");
  30. ageScoreAvg.forEach((k,v) -> System.out.println("key: " + k + " , " + "value: " + v));