首页 > 编程学习 > java8 分组

java8 分组

发布时间:2022/5/14 18:48:44

1. 多个分组

 Map<Long,Map<Long,List<RStudentExam>>> map = list
            .stream()
            .collect(Collectors.groupingBy(RStudentExam::getId,Collectors.groupingBy(RStudentExam::getSchoolId)));

2. 分组后求和

 参考链接:

https://blog.csdn.net/weixin_44905182/article/details/105792291

需求:

求得每个学生的总成绩

模拟数据如下:

  List<StudentScore> studentScoreList = new ArrayList<>();

        StudentScore studentScore1 = new StudentScore("慕容皝","语文",BigDecimal.valueOf(99));
        StudentScore studentScore2 = new StudentScore("慕容皝","数学",BigDecimal.valueOf(99));
        StudentScore studentScore3 = new StudentScore("慕容皝","英语",BigDecimal.valueOf(97));
        StudentScore studentScore4 = new StudentScore("慕容皝","历史",BigDecimal.valueOf(97));
        studentScoreList.add(studentScore1) ;
        studentScoreList.add(studentScore2) ;
        studentScoreList.add(studentScore3) ;
        studentScoreList.add(studentScore4) ;


        StudentScore studentScore5 = new StudentScore("慕容垂","语文",BigDecimal.valueOf(89));
        StudentScore studentScore6 = new StudentScore("慕容垂","数学",BigDecimal.valueOf(89));
        StudentScore studentScore7 = new StudentScore("慕容垂","英语",BigDecimal.valueOf(87));
        StudentScore studentScore8 = new StudentScore("慕容垂","历史",BigDecimal.valueOf(87));
        studentScoreList.add(studentScore5) ;
        studentScoreList.add(studentScore6) ;
        studentScoreList.add(studentScore7) ;
        studentScoreList.add(studentScore8) ;


        StudentScore studentScore9 = new StudentScore("慕容雪","语文",BigDecimal.valueOf(79));
        StudentScore studentScore10 = new StudentScore("慕容雪","数学",BigDecimal.valueOf(79));
        StudentScore studentScore11 = new StudentScore("慕容雪","英语",BigDecimal.valueOf(77));
        StudentScore studentScore12 = new StudentScore("慕容雪","历史",BigDecimal.valueOf(77));

        studentScoreList.add(studentScore9) ;
        studentScoreList.add(studentScore10) ;
        studentScoreList.add(studentScore11) ;
        studentScoreList.add(studentScore12) ;

 

常规做法:

map 的merge 方法

java8 分组后对组内数据的处理(扩展)

常规:

  // 法① 常规做法
        Map<String, BigDecimal> studentScoreMap1 = new HashMap<>();
        studentScoreList.forEach(studentScore -> {
            if (studentScoreMap1.containsKey(studentScore.getName())) {
                studentScoreMap1.put(studentScore.getName(),
                        // 拿到旧值,在原来的基础上操作
                        studentScoreMap1.get(studentScore.getName()).add(studentScore.getScore()));
            } else {
                studentScoreMap1.put(studentScore.getName(), studentScore.getScore());
            }
        });
        studentScoreMap1.forEach((k,v) -> System.out.println("key: " + k + " , " + "value: " + v));

        System.out.println("-----------------------------sum----------------------");

 

merge:

// 法②
        Map<String, BigDecimal> studentScoreMap2 = new HashMap<>();
        studentScoreList.forEach(studentScore -> studentScoreMap2.merge(
                // key
                studentScore.getName(),
                // value
                studentScore.getScore(),
                (a,b) ->{
                    // add 是返回一个新的 BigDecimal 对象
                    a = a.add(b);
                    return a;
                }));
        studentScoreMap2.forEach((k,v) -> System.out.println("key: " + k + " , " + "value: " + v));

 

merge方法定义在 java.util.Map 中,方法定义如下:

default V merge(K key, V value,
            BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
        Objects.requireNonNull(remappingFunction);
        Objects.requireNonNull(value);
        // 获取旧值
        V oldValue = get(key);
        // 旧值为null ,用value 直接作为新value ; 旧值非null ,执行 函数接口
        V newValue = (oldValue == null) ? value :
                   remappingFunction.apply(oldValue, value);
        if(newValue == null) {
            remove(key);
        } else {
            // insert  or update
            put(key, newValue);
        }
        return newValue;
    }

 

BiFunction 定义:

@FunctionalInterface
public interface BiFunction<T, U, R> {

    /**
     * Applies this function to the given arguments
     * @param t the first function argument
     * @param u the second function argument
     * @return the function result
     */
    R apply(T t, U u);
}

法③

需要自定义 函数式接口 etc(参考int 的算法,比较麻烦)

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

        System.out.println("-----------------------------sum 3.1 ----------------------");
        Map<String,BigDecimalSummaryStatistics> studentScoreMap4 =
                studentScoreList.stream()
                        .collect(Collectors.groupingBy(StudentScore::getName ,  CollectorsUtil.summarizingBigDecimal(StudentScore::getScore))   );

        studentScoreMap4.forEach((k,v) -> System.out.println("key: " + k + " , " + "value: " + v.getSum()));

 这个最常用:

  
public static <T, K> Collector<T, ?, Map<K, List<T>>>
    groupingBy(Function<? super T, ? extends K> classifier) {
        return groupingBy(classifier, toList());
    }

 

上面的用到的底层是下面的

  public static <T, K, A, D>
    Collector<T, ?, Map<K, D>> groupingBy(Function<? super T, ? extends K> classifier,
                                          Collector<? super T, A, D> downstream) {
        return groupingBy(classifier, HashMap::new, downstream);
    }

而上面两个方法的最底层调用的都是 下面的:

public static <T, K, D, A, M extends Map<K, D>>
    Collector<T, ?, M> groupingBy(Function<? super T, ? extends K> classifier,
                                  Supplier<M> mapFactory,
                                  Collector<? super T, A, D> downstream) {
        Supplier<A> downstreamSupplier = downstream.supplier();
        BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator();
        BiConsumer<Map<K, A>, T> accumulator = (m, t) -> {
            K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key");
            A container = m.computeIfAbsent(key, k -> downstreamSupplier.get());
            downstreamAccumulator.accept(container, t);
        };
        BinaryOperator<Map<K, A>> merger = Collectors.<K, A, Map<K, A>>mapMerger(downstream.combiner());
        @SuppressWarnings("unchecked")
        Supplier<Map<K, A>> mangledFactory = (Supplier<Map<K, A>>) mapFactory;

        if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) {
            return new CollectorImpl<>(mangledFactory, accumulator, merger, CH_ID);
        }
        else {
            @SuppressWarnings("unchecked")
            Function<A, A> downstreamFinisher = (Function<A, A>) downstream.finisher();
            Function<Map<K, A>, M> finisher = intermediate -> {
                intermediate.replaceAll((k, v) -> downstreamFinisher.apply(v));
                @SuppressWarnings("unchecked")
                M castResult = (M) intermediate;
                return castResult;
            };
            return new CollectorImpl<>(mangledFactory, accumulator, merger, finisher, CH_NOID);
        }
    }

对分组后,组内数据是int 的求和

 Foo foo1 = new Foo(1, 2);
        Foo foo2 = new Foo(2, 23);
        Foo foo3 = new Foo(2, 6);
        List<Foo> list = new ArrayList<>(4);
        list.add(foo1);
        list.add(foo2);
        list.add(foo3);
        Map<Integer, IntSummaryStatistics> collect = list.stream().collect(Collectors.groupingBy(Foo::getCode, Collectors.summarizingInt(Foo::getCount)));
        IntSummaryStatistics statistics1 = collect.get(1);
        System.out.println(statistics1.getSum());
        System.out.println(statistics1.getAverage());
        System.out.println(statistics1.getMax());
        System.out.println(statistics1.getMin());
        System.out.println(statistics1.getCount());


 源码如下:

  public static <T>
    Collector<T, ?, IntSummaryStatistics> summarizingInt(ToIntFunction<? super T> mapper) {
        return new CollectorImpl<T, IntSummaryStatistics, IntSummaryStatistics>(
                IntSummaryStatistics::new,
                (r, t) -> r.accept(mapper.applyAsInt(t)),
                (l, r) -> { l.combine(r); return l; }, CH_ID);
    }

 构造器定义如下:

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);
        }

package java.util;

import java.util.function.IntConsumer;
import java.util.stream.Collector;

/**
 * @since 1.8
 */
public class IntSummaryStatistics implements IntConsumer {
    private long count;
    private long sum;
    private int min = Integer.MAX_VALUE;
    private int max = Integer.MIN_VALUE;

   
    public IntSummaryStatistics() { }

   
    @Override
    public void accept(int value) {
        // 计数,求平均数用的
        ++count;
        // 求和
        sum += value;
        // 最小值
        min = Math.min(min, value);
        // 最大值
        max = Math.max(max, value);
    }

    // 计算对应的值
    public void combine(IntSummaryStatistics other) {
        count += other.count;
        sum += other.sum;
        min = Math.min(min, other.min);
        max = Math.max(max, other.max);
    }


    public final long getCount() {
        return count;
    }

    // 返回和 
    public final long getSum() {
        return sum;
    }

    // 返回最小值
    public final int getMin() {
        return min;
    }

    // 返回最大值
    public final int getMax() {
        return max;
    }

     // 返回平均值(sum 除以 count)
    public final double getAverage() {
        return getCount() > 0 ? (double) getSum() / getCount() : 0.0d;
    }

    @Override
    public String toString() {
        return String.format(
            "%s{count=%d, sum=%d, min=%d, average=%f, max=%d}",
            this.getClass().getSimpleName(),
            getCount(),
            getSum(),
            getMin(),
            getAverage(),
            getMax());
    }
}

 

而他的父接口是函数式接口

 


package java.util.function;

import java.util.Objects;

/**
 * @since 1.8
 */
@FunctionalInterface
public interface IntConsumer {

  
    void accept(int value);

  
}
 

 

@FunctionalInterface
public interface BiConsumer<T, U> {

    void accept(T t, U u);
}
@FunctionalInterface
public interface BinaryOperator<T> extends BiFunction<T,T,T>{

}

 

@FunctionalInterface
public interface BiFunction<T, U, R> {

    R apply(T t, U u);
}

自定义函数式接口

@FunctionalInterface
public interface ToIntFunction<T> {

    int applyAsInt(T value);
}

 

 

接下来改写 一个针对BigDecimal 类型的 group by

先定义初始化对象 ,返回对象

package com.example.demo.service.Impl;

import com.example.demo.entity.annotation.BigDecimalConsumer;

import java.math.BigDecimal;

/**
 * @author: guoyiguang
 **/
public class BigDecimalSummaryStatistics implements BigDecimalConsumer {

    private BigDecimal sum;
    public BigDecimalSummaryStatistics() { }


    public BigDecimal combine(BigDecimalSummaryStatistics other) {
     // 求和
      return   sum = sum.add(other.sum)  ;
    }
    @Override
    public void accept(BigDecimal value) {
        if (null  == sum){
            sum =  value ;
        }else {
            // 计算
            sum  = sum.add(value);
        }

    }

    @Override
    public String toString() {
        return "BigDecimalSummaryStatistics{" +
                "sum=" + sum +
                '}';
    }

     // 要获取到这个对象里的 sum 需要get 方法

    public BigDecimal getSum() {
        return sum;
    }
}

自定义函数式接口


@FunctionalInterface
public interface ToBigDecimalFunction<T> {
    // 传一个 ,返回 BigDecimal  对象
    BigDecimal applyAsBigDecimal(T value);
}

 提供一个返回  stream 流 里的 Collector 的工具类

 

package com.example.demo.utils;

import com.example.demo.entity.annotation.ToBigDecimalFunction;
import com.example.demo.service.Impl.BigDecimalSummaryStatistics;
import java.util.Collections;
import java.util.Set;
import java.util.function.*;
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;
    }

    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;
        }


        // 模仿int写的
        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;
        }
    }


    //  CollectorImpl(Supplier<A> supplier,
    //                      BiConsumer<A, T> accumulator,
    //                      BinaryOperator<A> combiner,
    //                      Set<Characteristics> characteristics)
//  T 不管
// 第一个 BigDecimalSummaryStatistics 是初始化对象
// 第二个  BigDecimalSummaryStatistics 是返回对象
    public static <T>
    Collector<T, BigDecimalSummaryStatistics, BigDecimalSummaryStatistics> summarizingBigDecimal(ToBigDecimalFunction<? super T>  mapper) {
//  T 不管
// 第一个 BigDecimalSummaryStatistics 是初始化对象
// 第二个  BigDecimalSummaryStatistics 是返回对象
        return new CollectorImpl<T, BigDecimalSummaryStatistics, BigDecimalSummaryStatistics>(
                BigDecimalSummaryStatistics::new  ,
                // 上一行 new 出来的 BigDecimalSummaryStatistics 对象作为 BiConsumer 的第一个参数
                (r, t) -> r.accept(mapper.applyAsBigDecimal(t)),
                // 上一行 new 出来的 BigDecimalSummaryStatistics 对象作为 BinaryOperator 的第二个参数
                (l, r) -> { l.combine(r); return l; }, CH_NOID);
    }

}

测试代码如下:

 

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

        System.out.println("-----------------------------sum 3.1 ----------------------");
        Map<String,BigDecimalSummaryStatistics> studentScoreMap4 =
                studentScoreList.stream()
                        .collect(Collectors.groupingBy(StudentScore::getName ,  CollectorsUtil.summarizingBigDecimal(StudentScore::getScore))   );

        studentScoreMap4.forEach((k,v) -> System.out.println("key: " + k + " , " + "value: " + v.getSum()));

测试结果:

-----------------------------sum 3.1 ----------------------
key: 慕容皝 , value: 392
key: 慕容垂 , value: 352
key: 慕容雪 , value: 312

 

 

Copyright © 2010-2022 ngui.cc 版权所有 |关于我们| 联系方式| 豫B2-20100000