实现一个自定义的Collector!

server/2024/9/23 7:38:58/

背景

当前有多个用户,产品提出一个需求,根据userStatus分组,然后将每个分组中的用户按照gender进行累加得到不同userStatus组下的gender总和 以map类型返回,而且要求使用stream.collect(Collector.groupingBy())方法一行写完;

解决思路

Collector.groupingBy()方法,默认可以轻松完成将用户按status分组,生成<Key, List<Val>>的map。但是,需求需要我们额外实现对于List中对象的gender属性进行累加的操作,此时就需要我们自定义一个collector来完成该操作并传入Collector.groupingBy()方法中~

实操

先上代码:

java">@Test  
void userCombine() {  User user1 = new User();  user1.setUserName("user1");  user1.setGender(10);  user1.setUserStatus(1);  User user2 = new User();  user2.setUserName("user2");  user2.setGender(3);  user2.setUserStatus(1);  User user3 = new User();  user3.setUserName("user3");  user3.setGender(13);  user3.setUserStatus(6);  List<User> users = Arrays.asList(user1, user2, user3);  // 根据userStatus分组,然后将每个分组中的用户按照gender进行累加得到不同userStatus组下的gender总和 以map类型返回,使用stream.collect(Collector.groupBy())方法  Map<Integer, Integer> collect = users.stream().collect(Collectors.groupingBy(User::getUserStatus,  Collector.of(() -> new int[1]  // 注意此处不能直接返回0,其并不是可变的容器, (sum, user) -> sum[0] +=  user.getGender(), (sum1, sum2) -> {  sum1[0] += sum2[0];  return sum1;  }, sum -> sum[0])));  System.out.println(collect);  
}

collector是什么?

首先,collector是什么?

在 Java Stream API 中,Collector 接口用于收集流中的元素,并将其转换为另一种形式,比如转换成集合、计算汇总统计信息等。

我们来看看Collector的构造函数,Collector.of()

java">  
/**  * Returns a new {@code Collector} described by the given {@code supplier},  * {@code accumulator}, {@code combiner}, and {@code finisher} functions.  * * @param supplier The supplier function for the new collector  * @param accumulator The accumulator function for the new collector  * @param combiner The combiner function for the new collector  * @param finisher The finisher function for the new collector  * @param characteristics The collector characteristics for the new  *                        collector * @param <T> The type of input elements for the new collector  * @param <A> The intermediate accumulation type of the new collector  * @param <R> The final result type of the new collector  * @throws NullPointerException if any argument is null  * @return the new {@code Collector}  */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) {......}

可以看到Collector 接口有三个重要的方法:supplier、accumulator 和 combiner,它们分别对应着收集器的不同阶段。在实现collector的过程中,这三个函数都需要我们自己实现,下面详细分析各个函数~

supplier函数是什么?

Supplier 是 Java 8 中引入的一个函数式接口,它位于 java.util.function 包中。Supplier 接口只有一个抽象方法 get(),该方法不接受任何参数,并返回一个类型为 T 的结果。Supplier 主要用于生成或提供一个对象实例,通常用于延迟初始化或创建对象。

java">@FunctionalInterface
public interface Supplier<T> {T get();
}

示例
假设你需要创建一个 User 对象,你可以使用 Supplier 如下所示:

java">Supplier<User> userSupplier = () -> new User("John Doe", 30);
User user = userSupplier.get(); // 创建并返回一个User对象

通俗的来说,他就是java定义的一个不需要输入,只管生成的方法~

supplier 是一个 Supplier 函数,它负责提供一个初始的可变结果容器。这个容器用于存储流中的元素或计算的结果。

为什么需要:在收集过程开始之前,需要有一个初始的容器来存储结果。supplier 方法提供了这样一个容器的实例。例如,如果你想要收集元素到一个列表中,supplier 可能会返回一个空列表。

BiConsumer函数是什么?

BiConsumer 是 Java 8 中引入的一个函数式接口,它位于 java.util.function 包中。BiConsumer 接口代表了一个接受两个输入参数且不返回任何内容的操作。它主要用于消费两个输入参数而不产生任何结果。

java">@FunctionalInterface
public interface BiConsumer<T, U> {void accept(T t, U u);default BiConsumer<T, U> andThen(BiConsumer<? super T, ? super U> after) {Objects.requireNonNull(after);return (T t, U u) -> { accept(t, u); after.accept(t, u); };}
}

BiConsumer 接口的主要方法
accept(T t, U u):这是一个功能性方法,它接受两个参数 t 和 u,并执行某些操作。此方法不返回任何值。

在collecor中该方法充当accumulator的角色,它负责将流中的元素累积到一个可变的结果容器中(supplier函数生成的容器)。每当流中的一个元素被处理时,accumulator 就会被调用来更新结果容器。

例如在将一个个user放到List中时,此时T就是list 和 U 就是user,而accumulator就需要定义user是如何放入list中,是否需要什么额外的操作,对应常见List的add操作~

BinaryOperator函数是什么?

BinaryOperator 是 Java 8 中引入的一个函数式接口,它位于 java.util.function 包中。BinaryOperator 接口代表了一个接受两个同类型的输入参数,并返回相同类型的单个结果的操作。它通常用于处理两个输入参数,并返回一个与输入参数类型相同的输出。

java">@FunctionalInterface
public interface BinaryOperator<T> extends BiFunction<T,T,T> {T apply(T t, T u);default BinaryOperator<T> andThen(BinaryOperator<? super T> after) {Objects.requireNonNull(after);return (T t, T u) -> after.apply(apply(t, u), u);}static <T> BinaryOperator<T> minBy(Comparator<? super T> comparator) {Objects.requireNonNull(comparator);return (a, b) -> comparator.compare(a, b) <= 0 ? a : b;}static <T> BinaryOperator<T> maxBy(Comparator<? super T> comparator) {Objects.requireNonNull(comparator);return (a, b) -> comparator.compare(a, b) >= 0 ? a : b;}
}

BinaryOperator 接口的主要方法就是 apply(T t, T u):这是一个功能性方法,它接受两个同类型的参数 t 和 u,并返回一个同类型的值。

在collecor中该方法充当combiner的角色,它负责将分开的两个流进行合并。例如当数据量很大时,流可能会被并行处理,这意味着流会被分成多个部分,每个部分都独立地进行处理。combiner 被用来合并这些部分的结果。

Function 函数是什么?

Function 同样是 Java 8 中引入的一个函数式接口,同样位于 java.util.function 包中。Function 接口有一个抽象方法 apply(),该方法接受一个类型为 T 的参数,并返回一个类型为 R 的结果。Function 主要用于将一个输入转换为另一个输出。

java">@FunctionalInterface
public interface Function<T, R> {R apply(T t);
}

示例
假设你需要将一个字符串转换为大写,你可以使用 Function 如下所示:

java">Function<String, String> toUpperCaseFunction = String::toUpperCase;
String upperCaseString = toUpperCaseFunction.apply("hello world"); // "HELLO WORLD"

通俗的来说,他就是用于将一个输入转换为另一个输出,接受一个参数,并返回一个结果,类似于stream.map()~

在collecor中该方法充当finisher的角色,它负责将中间结果转换成最终我们需要的对象~


http://www.ppmy.cn/server/101372.html

相关文章

【数据结构与算法】图

图目录 一.图的原理二.图的表示1.邻接列表2.邻接矩阵 三.图的结构——邻接表四.邻接表的初始化五.邻接表的创建六.完整代码 一.图的原理 图在我们的日常生活中,可谓是应用广泛,最长见的就有地图. 图可以是双向的,也可以是单向的. 图是一种由节点和边组成的数据结构. 节点&…

android FD_SET_chk问题定位

android FD_SET_chk问题定位 一、FD报错二、问题定位2.1 APM定位2.2 adb定位2.3. 代码获取FD数 三、FD优化 一、FD报错 App在运行中记录报错如下&#xff0c;FD_SET&#xff0c;这个问题大概是文件描述符&#xff08;File Descriptor&#xff0c;简称FD&#xff09;超过了最大…

2024新型数字政府综合解决方案(三)

新型数字政府综合解决方案通过融合人工智能、大数据和云计算技术&#xff0c;建立了一个智能化、互联互通的政府服务平台&#xff0c;旨在提升政府服务效率与透明度。该方案通过全面数字化政务流程&#xff0c;实现数据的实时共享和自动化处理&#xff0c;使公众能够便捷地访问…

map/set和unordered_map/unordered_set的区别及使用情况

map/set和unordered_map/unordered_set的区别 容器底层数据结构是否有序实现版本复杂度迭代器map/set红黑树有序C98O(logN&#xff09;双向迭代器unordered_map/unordered_set哈希表/散列表无序C11O(1)单向迭代器 unordered_set无序的&#xff08;VS下&#xff09; void uno…

C#工具库-NPOI

一、简介 NPOI是一个基于c#语言的&#xff0c;开源的&#xff0c;能够在不安装Microsoft Office组件的条件下读写Microsoft Office 的库。前身是Java的POI库,有“先贤”将其翻译成了c#语言的库&#xff0c;而这种由java到c#库的演变并非个例&#xff0c;比如DotNetty之于Netty,…

LabVIEW光伏微网实验系统

开发了一个基于LabVIEW的光伏微网实验系统&#xff0c;系统主要服务于工程教育和技术研究&#xff0c;以提高学生对分布式电力系统的理解和操作能力。该实验系统能够模拟光伏微网的各种运行状态&#xff0c;包括能量的生成、存储和消费等&#xff0c;特别是在无电网状态下的独立…

Windows禁止应用联网

转自两种方法阻止电脑上的软件彻底联网&#xff01; - 知乎 (zhihu.com) 但为了稳妥&#xff0c;自己还是稍微记录一下 1、创建bat脚本文件 创建文本-将下面的代码填入-保存为.bat文件 Echo Off SetLocal:beginecho: echo ****** 禁止文件夹联网 ****** echo:set /p folder…

C++STL初阶(12):stack和queue的初阶实现

1. stack的选型 对于栈的实现是我们非常熟悉的过程&#xff1a; C语言基础数据结构——栈和队列_栈和队列 插入取出数据-CSDN博客 _top表示下标&#xff0c;_capacity表示空间大小&#xff1a; 那么按照我们原来的思路&#xff0c;利用_top和_capacity T*来给stack构形。 temp…