java8 分组

el/2023/10/1 3:31:59

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(// keystudentScore.getName(),// valuestudentScore.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 updateput(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() { }@Overridepublic 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;}@Overridepublic 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)  ;}@Overridepublic void accept(BigDecimal value) {if (null  == sum){sum =  value ;}else {// 计算sum  = sum.add(value);}}@Overridepublic 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);}@Overridepublic BiConsumer<A, T> accumulator() {return accumulator;}@Overridepublic Supplier<A> supplier() {return supplier;}@Overridepublic BinaryOperator<A> combiner() {return combiner;}@Overridepublic Function<A, R> finisher() {return finisher;}@Overridepublic 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

 

 


http://www.ngui.cc/el/414511.html

相关文章

暂停触发器

alter table 你的表名 disable trigger all-- 禁用 再执行删除你的语句之前先执行这句,这样就禁用 触发器了 alter table 你的表名 enable trigger all-- 企用

cxgrid上如何取FOOTER上合计的值

View_Client.DataController.Summary.FooterSummaryValues[0],//得到值 View_Client.DataController.Summary.FooterSummaryTexts //得到显示文字 View_Client.DataController.Summary.FooterSummarys //得到合计对象 得到variant类型的值.

cxgrid复制粘贴操作

1、uses clipbrd; 2、复制 procedure TForm1.cxButton1Click(Sender: TObject); var p1,p2:integer; p3:string; begin p1:cxGrid5DBTableView1.Controller.FocusedRowIndex; p2:cxGrid5DBTableView1.Controller.FocusedColumnIndex; p3:cxGrid5DBTableView1.DataController.Va…

cxgrid控件出现Control '' has no parent window错误的解决

procedure TFrmgoodsedit.cxGrid1DBTableView1Column1PropertiesButtonClick( Sender: TObject; AButtonIndex: Integer); begin cdssub.edit; cdssub.FieldByName(货品id).AsInteger : -1; cdssub.FieldByName(编码).AsString : ; cdssub.FieldByName(名…

动态设置和访问cxgrid列的Properties

设置&#xff1a; cxGrid1DBTableView1Column.PropertiesClass TcxTextEditProperties; cxGrid1DBTableView1Column.PropertiesClass TcxDateEditProperties; cxGrid1DBTableView1Column.PropertiesClass TcxCalcEditProperties; cxGrid1DBTableVi…