评论

收藏

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

编程语言 编程语言 发布于:2021-08-16 16:43 | 阅读数:262 | 评论:0

业务中需要将一组数据分类后收集总和,原本可以使用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);
  }
}
以上为个人经验,希望能给大家一个参考,也希望大家多多。如有错误或未考虑完全的地方,望不吝赐教。
原文链接:https://jaemon.blog.csdn.net/article/details/103405970

关注下面的标签,发现更多相似文章