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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/308765.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

超维空间S2无人机使用说明书——51、基础版——使用yolov8进行目标跟踪

引言&#xff1a;为了提高yolo识别的质量&#xff0c;提高了yolo的版本&#xff0c;改用yolov8进行物体识别&#xff0c;同时系统兼容了低版本的yolo&#xff0c;包括基于C的yolov3和yolov4&#xff0c;以及yolov7。 简介&#xff0c;为了提高识别速度&#xff0c;系统采用了G…

数据结构与算法-排序

&#x1f31e;入冬 时寒 添衣 勿病 要开心 排序 &#x1f388;1.排序的基本概念&#x1f388;2.排序的分类&#x1f52d;2.1插入排序&#x1f50e;2.1.1直接插入排序&#x1f50e;2.1.2折半插入排序&#x1f50e;2.1.3希尔排序 &#x1f52d;2.2交换排序&#x1f50e;2.2.1冒泡…

07-项目打包 React Hooks

项目打包 项目打包是为了把整个项目都打包成最纯粹的js&#xff0c;让浏览器可以直接执行 打包命令已经在package.json里面定义好了 运行命令&#xff1a;npm run build&#xff0c;执行时间取决于第三方插件的数量以及电脑配置 打包完之后再build文件夹下&#xff0c;这个…

啊?这也算事务?!

作者简介&#xff1a;大家好&#xff0c;我是smart哥&#xff0c;前中兴通讯、美团架构师&#xff0c;现某互联网公司CTO 联系qq&#xff1a;184480602&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗互联网寒冬 学习必须往深处挖&…

Spring Boot学习随笔- 集成MyBatis-Plus,第一个MP程序(环境搭建、@TableName、@TableId、@TableField示例)

学习视频&#xff1a;【编程不良人】Mybatis-Plus整合SpringBoot实战教程,提高的你开发效率,后端人员必备! 引言 MyBatis-Plus是一个基于MyBatis的增强工具&#xff0c;旨在简化开发&#xff0c;提高效率。它扩展了MyBatis的功能&#xff0c;提供了许多实用的特性&#xff0c;…

golang第六卷---go命令

go命令 go/go helpgo versiongo envgo buggo buildgo installgo getgo modgo rungo cleango docgo fixgo fmtgo generatego workgo testgo toolgo vet go/go help 通过该命令&#xff0c;我们可以查看go语言中的所有命令&#xff0c;其中go与go help两个命令是等效的 如下&…

实时数仓应用价值(上)

欢迎关注WX公众号&#xff1a;数据运营入表资产化服务 获取更多算法源码材料 2023数据资源入表白皮书&#xff0c;推荐系统源码下载-CSDN博客 浅析研发支出费用化和资本化的区别-CSDN博客 商业银行数据资产估值白皮书&#xff0c;推荐系统源码下载-CSDN博客 用友BIP数据资…

计算机网络【EPoll原理】

预备知识&#xff1a;内核poll钩子原理 内核函数poll_wait 把当前进程加入到驱动里自定义的等待队列上 &#xff1b; 当驱动事件就绪后&#xff0c;就可以在驱动里自定义的等待队列上唤醒调用poll的进程&#xff1b; 故poll_wait作用&#xff1a;可以让驱动知道事件就绪的时…

笔记1:基于锚框(先验框)的目标检测

一、边缘框&#xff08;bounding box&#xff09; 1.1 定义 边缘框&#xff1a;真实标注的物体位置 2.1 表示方式 1、&#xff08;x1,y1)和(x2,y2) 2、&#xff08;x1,y1)和w,h 二、锚框(anchor box)/先验框&#xff08;prior bounding box&#xff09; 2.1 定义 对边缘…

DDC和PLC的区别

前言 PLC与DDC控制器的比较&#xff0c;一直以来在相关领域内受到广泛关注。每个人站在不同的角度分析&#xff0c;都会有不同的结论&#xff0c;我们今天聊聊这个话题。 基本定义和功能 可编程控制器PLC与直接数字控制器DDC&#xff0c;两者都由CPU模块、I/O模块、显示模块…

Python 内置高阶函数练习(Leetcode500.键盘行)

Python 内置高阶函数练习&#xff08;Leetcode500.键盘行&#xff09; 【一】试题 &#xff08;1&#xff09;地址&#xff1a; 500. 键盘行 - 力扣&#xff08;LeetCode&#xff09; &#xff08;2&#xff09;题目 给你一个字符串数组 words &#xff0c;只返回可以使用在…

可移动磁盘上的文件删除了怎么恢复?详细教程介绍

在我们的日常生活和工作中&#xff0c;可移动磁盘作为一种便携式的存储设备&#xff0c;经常被用来备份和传输数据。然而&#xff0c;有时候由于误操作或不小心的删除&#xff0c;导致可移动磁盘上的文件丢失。这些文件可能包含重要的工作资料、个人照片、视频等&#xff0c;一…