Collector收集器的高级用法

2023-12-30 09:28

本文主要是介绍Collector收集器的高级用法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Collectors收集器的高级用法

pexels-pixabay-265631

 

场景1:获取关联的班级名称

原先如果需要通过关联字段拿到其他表的某个字段,只能遍历List匹配获取

for (Student student : studentList) {Long clazzId = student.getClazzId();// 遍历班级列表,获取学生对应班级名称for (Clazz clazz : clazzList) {if(ObjectUtil.equal(clazzId, clazz.getClazzId())) {student.setClazzName(clazz.getClazzName());break;}}
}

但是如果使用 toMap 方法,可以一步到位,代码的可读性是不是要比上面那种方式好很多?

Map<Long, String> clazzMap = clazzList.stream().collect(Collectors.toMap(Clazz::getClazzId, Clazz::getClazzName));
// 使用Map进行匹配,直接通过get方法获取班级名称
studentList.forEach(i -> i.setClazzName(clazzMap.get(i.getClazzId())));

如果你想关联整个对象而不是某个字段,也没关系,可以像下面这样

Map<Long, Clazz> clazzMap = clazzList.stream().collect(Collectors.toMap(Clazz::getClazzId, Function.identity()));
// 使用Map关联班级对象
studentList.forEach(i -> i.setClazz(clazzMap.get(i.getClazzId())));

 

场景2:统计图书的借阅次数

有一些时候,我们需要对列表的数据做一些统计,比如图书的借阅次数,活动的参与人数等,这些统计可以通过循环手动遍历进行计算

for (BookInfo bookInfo : bookList) {long borrowNumber = 0L;Long bookId = bookInfo.getBookId();for (BorrowRecord record : recordList) {// 次数+1if(ObjectUtil.equal(bookId, record.getBookId())) {borrowNumber ++;}}bookInfo.setBorrowNumber(borrowNumber);
}

上面的这种写法其实还好,但是业务如果复杂一些的话,写起来就比较麻烦了,但是如果使用 toMap 方法,可以一步到位

Map<Long, Long> numberMap = recordList.stream().collect(Collectors.toMap(BorrowRecord::getBookId, e -> 1L, Long::sum));
// 统计图书的借阅次数
bookList.forEach(i -> i.setBorrowNumber(numberMap.get(i.getBookId())));

 

场景3:根据城市分组,查看城市都有哪些姓氏的人

有些业务场景比较复杂,需要对我们对数据进行分组统计,这些情况下,就需要用到 groupingBy() 方法了

Map<City, Set<String>> lastNamesByCity= people.stream().collect(Collectors.groupingBy(Person::getCity,Collectors.mapping(Person::getLastName, Collectors.toSet())));

上面的方法,其实不是唯一的写法,我们还可以这样写

Map<City, Set<String>> lastNamesByCity= people.stream().collect(Collectors.groupingBy(Person::getCity,Collectors.flatMapping((i) -> Stream.of(i.getLastName()), Collectors.toSet())));

Map 也可以间接实现分组的效果,让我们换成 toMap() 方法试试

Map<City, Set<String>> lastNamesByCity= people.stream().collect(Collectors.toMap(Person::getCity, (v) -> {Set<String> set = Sets.newHashSet();set.add(v.getLastName());return set;},(a, b) -> {(a).addAll(b);return a;}, HashMap::new));

另外,如果最后的统计不要求姓氏写成集合,那么我们还可以写成这样

 Map<City, String> lastNamesByCity= people.stream().collect(Collectors.toMap(Person::getCity,Person::getLastName, (a, b) -> a + "," + b));

能看得出来,在分组这件事上,groupingBy() 方法更适合,使用 toMap() 方法虽然也能实现,但是写出的代码会更复杂。

 

场景4:根据客户名称分组,查看订单都有哪些商品

如果需要做购物商城一类的项目,那么必然就离不开订单、用户和商品,根据客户统计订单商品,也是一个非常复杂的业务逻辑,因此这里我们可以用到 groupingBy() 方法

Map<String, Set<Product>> productsByCustomerName= orders.stream().collect(Collectors.groupingBy(Order::getCustomName,Collectors.flatMapping(order -> order.getProducts().stream(),Collectors.toSet())));

让我们换一种写法试试

Map<String, Set<Product>> productsByCustomerName= orders.stream().collect(Collectors.groupingBy(Order::getCustomName,Collectors.collectingAndThen(Collectors.toSet(),i -> i.stream().flatMap(p -> p.getProducts().stream()).collect(Collectors.toSet()))));

换成 toMap() 如何

Map<String, Set<Product>> productsByCustomerName= orders.stream().collect(Collectors.toMap(Order::getCustomName,(v) -> Sets.newHashSet(v.getProducts()),(a, b) -> {(a).addAll(b);return a;})
);

 

场景5:根据部门分组,查看工资大于2000的员工

说到部门,那就不得不提到人员,对人员的各种信息进行统计,我们依然可以使用 groupingBy() 方法

Map<Department, Set<Employee>> wellPaidEmployeesByDepartment= employees.stream().collect(Collectors.groupingBy(Employee::getDepartment,Collectors.filtering(e -> e.getSalary() > 2000,Collectors.toCollection(HashSet::new))));

同样地,如果你喜欢使用 toMap(),也可以像下面这样写

Map<Department, Set<Employee>> wellPaidEmployeesByDepartment= employees.stream().filter(e -> e.getSalary() > 2000).collect(Collectors.toMap(Employee::getDepartment,Sets::newHashSet,(a, b) -> {(a).addAll(b);return a;}));

 

场景6:区分及格和不及格的学生

统计学生的成绩是一大麻烦事,很多数据需要统计到,但如果只是区分及格和不及格的学生,这里我们可以使用 partitioningBy() 方法,将学生分为两个区间

 Map<Boolean, List<Student>> passingFailing = students.stream().collect(Collectors.partitioningBy(s -> s.getGrade() >= DataUtils.PASS_THRESHOLD));

partitioningBy 相当于另一种版本的 groupingBy,但是数据最多只有两组,因为 partitioningBy 是通过指定的条件进行分组的,满足的在一边,不满足的在另一边。

 

场景7:同时统计订单数以及综合评分

JDK12 开始,Collectors 新增了一个方法 teeing,直译为发球,这样翻译可能听不太懂,但我给你看一下怎么用,你就知道了

Pair<Map<Long, Long>, Map<Long, Double>> pair = orderList.stream().collect(Collectors.teeing(Collectors.groupingBy(BookOrder::getHotelId, Collectors.counting()),Collectors.groupingBy(BookOrder::getHotelId, Collectors.averagingDouble(BookOrder::getOrderRating)),Pair::of));
  Collectors.groupingBy(BookOrder::getHotelId, Collectors.counting()),Collectors.groupingBy(BookOrder::getHotelId, Collectors.averagingDouble(BookOrder::getOrderRating)),Pair::of));

是的,teeing 方法接收两个参数,这两个参数分别会得出一个结果,把两个结果再进行处理,就是第三个参数,就这么简单。利用这个方法我们可以分别统计两个结果(比如最值,平均数)并对这两个结果再进行处理,非常好用

这篇关于Collector收集器的高级用法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/552411

相关文章

JavaScript中的reduce方法执行过程、使用场景及进阶用法

《JavaScript中的reduce方法执行过程、使用场景及进阶用法》:本文主要介绍JavaScript中的reduce方法执行过程、使用场景及进阶用法的相关资料,reduce是JavaScri... 目录1. 什么是reduce2. reduce语法2.1 语法2.2 参数说明3. reduce执行过程

Python itertools中accumulate函数用法及使用运用详细讲解

《Pythonitertools中accumulate函数用法及使用运用详细讲解》:本文主要介绍Python的itertools库中的accumulate函数,该函数可以计算累积和或通过指定函数... 目录1.1前言:1.2定义:1.3衍生用法:1.3Leetcode的实际运用:总结 1.1前言:本文将详

MyBatis-Flex BaseMapper的接口基本用法小结

《MyBatis-FlexBaseMapper的接口基本用法小结》本文主要介绍了MyBatis-FlexBaseMapper的接口基本用法小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具... 目录MyBATis-Flex简单介绍特性基础方法INSERT① insert② insertSelec

深入解析Spring TransactionTemplate 高级用法(示例代码)

《深入解析SpringTransactionTemplate高级用法(示例代码)》TransactionTemplate是Spring框架中一个强大的工具,它允许开发者以编程方式控制事务,通过... 目录1. TransactionTemplate 的核心概念2. 核心接口和类3. TransactionT

数据库使用之union、union all、各种join的用法区别解析

《数据库使用之union、unionall、各种join的用法区别解析》:本文主要介绍SQL中的Union和UnionAll的区别,包括去重与否以及使用时的注意事项,还详细解释了Join关键字,... 目录一、Union 和Union All1、区别:2、注意点:3、具体举例二、Join关键字的区别&php

oracle中exists和not exists用法举例详解

《oracle中exists和notexists用法举例详解》:本文主要介绍oracle中exists和notexists用法的相关资料,EXISTS用于检测子查询是否返回任何行,而NOTE... 目录基本概念:举例语法pub_name总结 exists (sql 返回结果集为真)not exists (s

Python中列表的高级索引技巧分享

《Python中列表的高级索引技巧分享》列表是Python中最常用的数据结构之一,它允许你存储多个元素,并且可以通过索引来访问这些元素,本文将带你深入了解Python列表的高级索引技巧,希望对... 目录1.基本索引2.切片3.负数索引切片4.步长5.多维列表6.列表解析7.切片赋值8.删除元素9.反转列表

Springboot中Jackson用法详解

《Springboot中Jackson用法详解》Springboot自带默认json解析Jackson,可以在不引入其他json解析包情况下,解析json字段,下面我们就来聊聊Springboot中J... 目录前言Jackson用法将对象解析为json字符串将json解析为对象将json文件转换为json

正则表达式高级应用与性能优化记录

《正则表达式高级应用与性能优化记录》本文介绍了正则表达式的高级应用和性能优化技巧,包括文本拆分、合并、XML/HTML解析、数据分析、以及性能优化方法,通过这些技巧,可以更高效地利用正则表达式进行复杂... 目录第6章:正则表达式的高级应用6.1 模式匹配与文本处理6.1.1 文本拆分6.1.2 文本合并6

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识