java8特性:Collectors.groupingBy进行分组、排序等操作 (二)

参考博文

  Stream类的函数

<R, A> R collect(Collector<? super T, A, R> collector);

可以对数据集进行简单的分组统计。函数参数为接口Collector,其实现在final class Collectors的内部静态类CollectorImpl。Collector接口代码如下:

public interface Collector<T, A, R> {

    Supplier<A> supplier();

    BiConsumer<A, T> accumulator();

    BinaryOperator<A> combiner();

    Function<A, R> finisher();

    Set<Characteristics> characteristics();

    public static<T, R> Collector<T, R, R> of(Supplier<R> supplier,
                                              BiConsumer<R, T> accumulator,
                                              BinaryOperator<R> combiner,
                                              Characteristics... characteristics) {
        Objects.requireNonNull(supplier);
        Objects.requireNonNull(accumulator);
        Objects.requireNonNull(combiner);
        Objects.requireNonNull(characteristics);
        Set<Characteristics> cs = (characteristics.length == 0)
                                  ? Collectors.CH_ID
                                  : Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH,
                                                                           characteristics));
        return new Collectors.CollectorImpl<>(supplier, accumulator, combiner, cs);
    }
    public static<T, A, R> Collector<T, A, R> of(Supplier<A> supplier,
                                                 BiConsumer<A, T> accumulator,
                                                 BinaryOperator<A> combiner,
                                                 Function<A, R> finisher,
                                                 Characteristics... characteristics) {
        Objects.requireNonNull(supplier);
        Objects.requireNonNull(accumulator);
        Objects.requireNonNull(combiner);
        Objects.requireNonNull(finisher);
        Objects.requireNonNull(characteristics);
        Set<Characteristics> cs = Collectors.CH_NOID;
        if (characteristics.length > 0) {
            cs = EnumSet.noneOf(Characteristics.class);
            Collections.addAll(cs, characteristics);
            cs = Collections.unmodifiableSet(cs);
        }
        return new Collectors.CollectorImpl<>(supplier, accumulator, combiner, finisher, cs);
    }
    enum Characteristics {
        CONCURRENT,
        UNORDERED,
        IDENTITY_FINISH
    }

}
Collectors

  Collectors中静态内部类实现了Collector接口,并且提供了诸如求最大值、最小值、平均值及求和等函数,可以搭配groupingBy(XXX)使用对数据集进行分组,相关函数及使用示例如下:

1. Collectors.summingInt(XXX)

  summingInt源码:
  


    /**
     * 静态函数
     * 返回一个Collector接口,其可用于产生输入元素‘int型和’的函数
     *
     * @param <T> 输入元素类型
     * @param mapper 函数,抽出需要汇总值得属性
     * @return Collector ,用于产生'驱动属性'的和
     */
    public static <T> Collector<T, ?, Integer>
    summingInt(ToIntFunction<? super T> mapper) {
        return new Collectors.CollectorImpl<>(
                () -> new int[1],//Supplier<A> === T get();
                (a, t) -> { a[0] += mapper.applyAsInt(t); },//BiConsumer<A, T> === void accept(T t, U u)
                (a, b) -> { a[0] += b[0]; return a; },// BinaryOperator<A> ===  R apply(T t, U u)
                a -> a[0], // Function<A,R> === R apply(T t);
                CH_NOID);// Set<Characteristics> == int size();
    }

参数ToIntFunction类源码

@FunctionalInterface
public interface ToIntFunction<T> {

    /**
     * Applies this function to the given argument.
     *
     * @param value 函数参数
     */
    int applyAsInt(T value);
}

返回值类所继承的接口Collector

/*
 * 包含
 *    1.返回值为函数类接口的抽象方法;
 *    2.of方法返回其对象实例;
 *    3.枚举类,包含
 *       CONCURRENT,UNORDERED,IDENTITY_FINISH三个元素
 */
public interface Collector<T, A, R> {

    Supplier<A> supplier();

    BiConsumer<A, T> accumulator();

    BinaryOperator<A> combiner();

    Function<A, R> finisher();

    Set<Characteristics> characteristics();

    /* 参数同其方法返回值类型
     * 用给的三个函数类接口实例初始化Collector接口继承类Collectors.CollectorImpl实例,并返回
     */
    public static<T, R> Collector<T, R, R> of(Supplier<R> supplier,
                                              BiConsumer<R, T> accumulator,
                                              BinaryOperator<R> combiner,
                                              Characteristics... characteristics) {
        Objects.requireNonNull(supplier);//保证函数类接口不为null,否则抛运行时异常
        Objects.requireNonNull(accumulator);//同上
        Objects.requireNonNull(combiner);//同上
        Objects.requireNonNull(characteristics);//同上
        Set<Characteristics> cs = (characteristics.length == 0)
                                  ? Collectors.CH_ID
                                  : Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH,
                                                                           characteristics));
        return new Collectors.CollectorImpl<>(supplier, accumulator, combiner, cs);
    }

    /*
     * 用给的三个函数类接口实例初始化Collector接口继承类Collectors.CollectorImpl实例,并返回
     */
    public static<T, A, R> Collector<T, A, R> of(Supplier<A> supplier,
                                                 BiConsumer<A, T> accumulator,
                                                 BinaryOperator<A> combiner,
                                                 Function<A, R> finisher,
                                                 Characteristics... characteristics) {
        Objects.requireNonNull(supplier);
        Objects.requireNonNull(accumulator);
        Objects.requireNonNull(combiner);
        Objects.requireNonNull(finisher);
        Objects.requireNonNull(characteristics);
        Set<Characteristics> cs = Collectors.CH_NOID;
        if (characteristics.length > 0) {
            cs = EnumSet.noneOf(Characteristics.class);
            Collections.addAll(cs, characteristics);
            cs = Collections.unmodifiableSet(cs);
        }
        return new Collectors.CollectorImpl<>(supplier, accumulator, combiner, finisher, cs);
    }

    enum Characteristics {

        CONCURRENT,

        UNORDERED,

        IDENTITY_FINISH
    }
}

Collectors.CollectorImpl,静态内部类

   /**
     * Simple implementation class for {@code Collector}.
     *   1.包含几个final变量,类型同继承接口Collector构造器参数,也同其抽象方法返回值;
     *   2.两个构造器,实现方式与Collector类似;
     *   3.重载的父类方法,用其变量赋值;
     */
    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;
        }
    }

TODO放一段求平均数和求和的函数代码,完全看不懂底层实现

  /**
   *求平均数
   */
    public static <T> Collector<T, ?, Double>
    averagingInt(ToIntFunction<? super T> mapper) {
        return new Collectors.CollectorImpl<>(
                () -> new long[2],
                (a, t) -> { a[0] += mapper.applyAsInt(t); a[1]++; },
                (a, b) -> { a[0] += b[0]; a[1] += b[1]; return a; },
                a -> (a[1] == 0) ? 0.0d : (double) a[0] / a[1],
                CH_NOID);
    }

 /**
   *求和
   */
    public static <T> Collector<T, ?, Integer>
    summingInt(ToIntFunction<? super T> mapper) {
        return new Collectors.CollectorImpl<>(
                () -> new int[1],
                (a, t) -> { a[0] += mapper.applyAsInt(t); },
                (a, b) -> { a[0] += b[0]; return a; },
                a -> a[0], CH_NOID);
    }
  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java8中,我们可以使用Stream API来对集合进行分组排序操作,其中Collectors.groupingBy是一个非常有用的方法。它接收一个Function作为参数,用于将元素映射为分组的键,返回一个Map类型的结果,其中键是由Function映射的结果,值是对应的元素列表。 例如,我们有一个Person类,其中包含姓名和年龄两个属性,我们想按照年龄进行分组: ``` List<Person> persons = Arrays.asList( new Person("John", 30), new Person("Jane", 25), new Person("Bob", 40), new Person("Mary", 35) ); Map<Integer, List<Person>> personsByAge = persons.stream() .collect(Collectors.groupingBy(Person::getAge)); personsByAge.forEach((age, list) -> System.out.println(age + " -> " + list)); ``` 输出结果为: ``` 25 -> [Person{name='Jane', age=25}] 30 -> [Person{name='John', age=30}] 35 -> [Person{name='Mary', age=35}] 40 -> [Person{name='Bob', age=40}] ``` 我们还可以对分组结果进行排序,例如按照年龄从小到大排序: ``` Map<Integer, List<Person>> personsByAgeSorted = persons.stream() .collect(Collectors.groupingBy(Person::getAge, TreeMap::new, Collectors.toList())); personsByAgeSorted.forEach((age, list) -> System.out.println(age + " -> " + list)); ``` 输出结果为: ``` 25 -> [Person{name='Jane', age=25}] 30 -> [Person{name='John', age=30}] 35 -> [Person{name='Mary', age=35}] 40 -> [Person{name='Bob', age=40}] ``` 在这个例子中,我们使用TreeMap作为分组结果的容器,实现了按照年龄从小到大排序的功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值