Java Stream API进阶篇
作者:CarpenterLee 发布时间:[ 2017/3/15 13:36:33 ] 推荐标签:测试开发技术 Java
使用collect()生成Map
前面已经说过 Stream 背后依赖于某种数据源,数据源可以是数组、容器等,但不能是 Map 。反过来从 Stream 生成 Map 是可以的,但我们要想清楚 Map 的 key 和 value 分别代表什么,根本原因是我们要想清楚要干什么。通常在三种情况下 collect() 的结果会是 Map :
使用 Collectors.toMap() 生成的收集器,用户需要指定如何生成 Map 的 key 和 value 。
使用 Collectors.partitioningBy() 生成的收集器,对元素进行二分区操作时用到。
使用 Collectors.groupingBy() 生成的收集器,对元素做 group 操作时用到。
情况1:使用 toMap() 生成的收集器,这种情况是直接的,前面例子中已提到,这是和 Collectors.toCollection() 并列的方法。如下代码展示将学生列表转换成由 <学生 gpa=""> 组成的 Map 。非常直观,无需多言。
// 使用toMap()统计学生GPA
Map<Student, Double> studentToGPA =
students.stream().collect(Collectors.toMap(Functions.identity(),// 如何生成key
student -> computeGPA(student)));// 如何生成value
情况2:使用 partitioningBy() 生成的收集器,这种情况适用于将 Stream 中的元素依据某个二值逻辑(满足条件,或不满足)分成互补相交的两部分,比如男女性别、成绩及格与否等。下列代码展示将学生分成成绩及格或不及格的两部分。
// Partition students into passing and failing
Map<Boolean, List<Student>> passingFailing = students.stream()
.collect(Collectors.partitioningBy(s -> s.getGrade() >= PASS_THRESHOLD));
情况3:使用 groupingBy() 生成的收集器,这是比较灵活的一种情况。跟SQL中的 group by 语句类似,这里的 groupingBy() 也是按照某个属性对数据进行分组,属性相同的元素会被对应到 Map 的同一个 key 上。下列代码展示将员工按照部门进行分组:
// Group employees by department
Map<Department, List<Employee>> byDept = employees.stream()
.collect(Collectors.groupingBy(Employee::getDepartment));
以上只是分组的基本用法,有些时候仅仅分组是不够的。在SQL中使用 group by 是为了协助其他查询,比如 1. 先将员工按照部门分组,2. 然后统计每个部门员工的人数 。Java类库设计者也考虑到了这种情况,增强版的 groupingBy() 能够满足这种需求。增强版的 groupingBy() 允许我们对元素分组之后再执行某种运算,比如求和、计数、平均值、类型转换等。这种先将元素分组的收集器叫做 上游收集器 ,之后执行其他运算的收集器叫做 下游收集器 ( downstream Collector )。
// 使用下游收集器统计每个部门的人数
Map<Department, Integer> totalByDept = employees.stream()
.collect(Collectors.groupingBy(Employee::getDepartment,
Collectors.counting()));// 下游收集器
上面代码的逻辑是不是越看越像SQL?高度非结构化。还有更狠的,下游收集器还可以包含更下游的收集器,这绝不是为了炫技而增加的把戏,而是实际场景需要。考虑将员工按照部门分组的场景,如果 我们想得到每个员工的名字(字符串),而不是一个个 Employee 对象 ,可通过如下方式做到:
// 按照部门对员工分布组,并只保留员工的名字
Map<Department, List<String>> byDept = employees.stream()
.collect(Collectors.groupingBy(Employee::getDepartment,
Collectors.mapping(Employee::getName,// 下游收集器
Collectors.toList())));// 更下游的收集器
如果看到这里你还没有对Java函数式编程失去信心,恭喜你,你已经顺利成为Java函数式编程大师了。
使用collect()做字符串join
这个肯定是大家喜闻乐见的功能,字符串拼接时使用 Collectors.joining() 生成的收集器,从此告别 for 循环。 Collectors.joining() 方法有三种重写形式,分别对应三种不同的拼接方式。无需多言,代码过目难忘。
// 使用Collectors.joining()拼接字符串
Stream<String> stream = Stream.of("I", "love", "you");
//String joined = stream.collect(Collectors.joining());// "Iloveyou"
//String joined = stream.collect(Collectors.joining(","));// "I,love,you"
String joined = stream.collect(Collectors.joining(",", "{", "}"));// "{I,love,you}"
collect()还可以做更多
除了可以使用 Collectors 工具类已经封装好的收集器,我们还可以自定义收集器,或者直接调用 collect(Supplier<R> supplier, BiConsumer<R,? super T> accumulator, BiConsumer<R,R> combiner) 方法, 收集任何形式你想要的信息 。不过 Collectors 工具类应该能满足我们的绝大部分需求,手动实现之间请先看看文档。
本文内容不用于商业目的,如涉及知识产权问题,请权利人联系SPASVO小编(021-61079698-8054),我们将立即处理,马上删除。
相关推荐
Java性能测试有哪些不为众人所知的原则?Java设计模式??装饰者模式谈谈Java中遍历Map的几种方法Java Web入门必知你需要理解的Java反射机制知识总结编写更好的Java单元测试的7个技巧编程常用的几种时间戳转换(java .net 数据库)适合Java开发者学习的Python入门教程Java webdriver如何获取浏览器新窗口中的元素?Java重写与重载(区别与用途)Java变量的分类与初始化JavaScript有这几种测试分类Java有哪四个核心技术?给 Java开发者的10个大数据工具和框架Java中几个常用设计模式汇总java生态圈常用技术框架、开源中间件,系统架构及经典案例等
更新发布
功能测试和接口测试的区别
2023/3/23 14:23:39如何写好测试用例文档
2023/3/22 16:17:39常用的选择回归测试的方式有哪些?
2022/6/14 16:14:27测试流程中需要重点把关几个过程?
2021/10/18 15:37:44性能测试的七种方法
2021/9/17 15:19:29全链路压测优化思路
2021/9/14 15:42:25性能测试流程浅谈
2021/5/28 17:25:47常见的APP性能测试指标
2021/5/8 17:01:11热门文章
常见的移动App Bug??崩溃的测试用例设计如何用Jmeter做压力测试QC使用说明APP压力测试入门教程移动app测试中的主要问题jenkins+testng+ant+webdriver持续集成测试使用JMeter进行HTTP负载测试Selenium 2.0 WebDriver 使用指南