一, Java Stream 管道数据处理操作
在本号之前写过的文章中, 曾经给大家介绍过 Java Stream 管道流是用于简化集合类元素处理的 java API. 在使用的过程中分为三个阶段. 在开始本文之前, 我觉得仍然需要给一些新朋友介绍一下这三个阶段, 如图:
第一阶段 (图中蓝色): 将集合, 数组, 或行文本文件转换为 java Stream 管道流
第二阶段 (图中虚线部分): 管道流式数据处理操作, 处理管道中的每一个元素. 上一个管道中的输出元素作为下一个管道的输入元素.
第三阶段 (图中绿色): 管道流结果处理操作, 也就是本文的将介绍的核心内容.
在开始学习之前, 仍然有必要回顾一下我们之前给大家讲过的一个例子:
- List<String> nameStrs = Arrays.asList("Monkey", "Lion", "Giraffe","Lemur");
- List<String> list = nameStrs.stream()
- .filter(s -> s.startsWith("L"))
- .map(String::toUpperCase)
- .sorted()
- .collect(toList());
- System.out.println(list);
首先使用 stream() 方法将字符串 List 转换为管道流 Stream
然后进行管道数据处理操作, 先用 fliter 函数过滤所有大写 L 开头的字符串, 然后将管道中的字符串转换为大写字母 toUpperCase, 然后调用 sorted 方法排序. 这些 API 的用法在本号之前的文章有介绍过. 其中还使用到了 lambda 表达式和函数引用.
最后使用 collect 函数进行结果处理, 将 java Stream 管道流转换为 List. 最终 list 的输出结果是:[LEMUR, LION]
如果你不使用 java Stream 管道流的话, 想一想你需要多少行代码完成上面的功能呢? 回到正题, 这篇文章就是要给大家介绍第三阶段: 对管道流处理结果都可以做哪些操作呢? 下面开始吧!
二, ForEach 和 ForEachOrdered
如果我们只是希望将 Stream 管道流的处理结果打印出来, 而不是进行类型转换, 我们就可以使用 forEach() 方法或 forEachOrdered() 方法.
- Stream.of("Monkey", "Lion", "Giraffe", "Lemur", "Lion")
- .parallel()
- .forEach(System.out::println);
- Stream.of("Monkey", "Lion", "Giraffe", "Lemur", "Lion")
- .parallel()
- .forEachOrdered(System.out::println);
parallel() 函数表示对管道中的元素进行并行处理, 而不是串行处理, 这样处理速度更快. 但是这样就有可能导致管道流中后面的元素先处理, 前面的元素后处理, 也就是元素的顺序无法保证
forEachOrdered 从名字上看就可以理解, 虽然在数据处理顺序上可能无法保障, 但是 forEachOrdered 方法可以在元素输出的顺序上保证与元素进入管道流的顺序一致. 也就是下面的样子 (forEach 方法则无法保证这个顺序):
- Monkey
- Lion
- Giraffe
- Lemur
- Lion
三, 元素的收集 collect
java Stream 最常见的用法就是: 一将集合类转换成管道流, 二对管道流数据处理, 三将管道流处理结果在转换成集合类. 那么 collect() 方法就为我们提供了这样的功能: 将管道流处理结果在转换成集合类.
3.1. 收集为 Set
通过 Collectors.toSet() 方法收集 Stream 的处理结果, 将所有元素收集到 Set 集合中.
- Set<String> collectToSet = Stream.of(
- "Monkey", "Lion", "Giraffe", "Lemur", "Lion"
- )
- .collect(Collectors.toSet());
- // 最终 collectToSet 中的元素是:[Monkey, Lion, Giraffe, Lemur], 注意 Set 会去重.
3.2. 收集到 List
同样, 可以将元素收集到 List 使用 toList() 收集器中.
- List<String> collectToList = Stream.of(
- "Monkey", "Lion", "Giraffe", "Lemur", "Lion"
- ).collect(Collectors.toList());
- // 最终 collectToList 中的元素是: [Monkey, Lion, Giraffe, Lemur, Lion]
3.3. 通用的收集方式
上面为大家介绍的元素收集方式, 都是专用的. 比如使用 Collectors.toSet() 收集为 Set 类型集合; 使用 Collectors.toList() 收集为 List 类型集合. 那么, 有没有一种比较通用的数据元素收集方式, 将数据收集为任意的 Collection 接口子类型.
所以, 这里就像大家介绍一种通用的元素收集方式, 你可以将数据元素收集到任意的 Collection 类型: 即向所需 Collection 类型提供构造函数的方式.
- LinkedList<String> collectToCollection = Stream.of(
- "Monkey", "Lion", "Giraffe", "Lemur", "Lion"
- ).collect(Collectors.toCollection(LinkedList::new));
- // 最终 collectToCollection 中的元素是: [Monkey, Lion, Giraffe, Lemur, Lion]
注意: 代码中使用了 LinkedList::new, 实际是调用 LinkedList 的构造函数, 将元素收集到 Linked List. 当然你还可以使用诸如 LinkedHashSet::new 和 PriorityQueue::new 将数据元素收集为其他的集合类型, 这样就比较通用了.
3.4. 收集到 Array
通过 toArray(String[]::new) 方法收集 Stream 的处理结果, 将所有元素收集到字符串数组中.
- String[] toArray = Stream.of(
- "Monkey", "Lion", "Giraffe", "Lemur", "Lion"
- ) .toArray(String[]::new);
- // 最终 toArray 字符串数组中的元素是: [Monkey, Lion, Giraffe, Lemur, Lion]
3.5. 收集到 Map
使用 Collectors.toMap() 方法将数据元素收集到 Map 里面, 但是出现一个问题: 那就是管道中的元素是作为 key, 还是作为 value. 我们用到了一个 Function.identity() 方法, 该方法很简单就是返回一个 "t -> t"(输入就是输出的 lambda 表达式). 另外使用管道流处理函数 distinct() 来确保 Map 键值的唯一性.
- Map<String, Integer> toMap = Stream.of(
- "Monkey", "Lion", "Giraffe", "Lemur", "Lion"
- )
- .distinct()
- .collect(Collectors.toMap(
- Function.identity(), // 元素输入就是输出, 作为 key
- s -> (int) s.chars().distinct().count()// 输入元素的不同的字母个数, 作为 value
- ));
- // 最终 toMap 的结果是: {Monkey=6, Lion=4, Lemur=5, Giraffe=6}
3.6. 分组收集 groupingBy
Collectors.groupingBy 用来实现元素的分组收集, 下面的代码演示如何根据首字母将不同的数据元素收集到不同的 List, 并封装为 Map.
- Map<Character, List<String>> groupingByList = Stream.of(
- "Monkey", "Lion", "Giraffe", "Lemur", "Lion"
- )
- .collect(Collectors.groupingBy(
- s -> s.charAt(0) , // 根据元素首字母分组, 相同的在一组
- // counting() // 加上这一行代码可以实现分组统计
- ));
- // 最终 groupingByList 内的元素: {G=[Giraffe], L=[Lion, Lemur, Lion], M=[Monkey]}
- // 如果加上 counting() , 结果是: {G=1, L=3, M=1}
四, 其他常用方法
- boolean containsTwo = IntStream.of(1, 2, 3).anyMatch(i -> i == 2);
- // 判断管道中是否包含 2, 结果是: true
- long nrOfAnimals = Stream.of(
- "Monkey", "Lion", "Giraffe", "Lemur"
- ).count();
- // 管道中元素数据总计结果 nrOfAnimals: 4
- int sum = IntStream.of(1, 2, 3).sum();
- // 管道中元素数据累加结果 sum: 6
- OptionalDouble average = IntStream.of(1, 2, 3).average();
- // 管道中元素数据平均值 average: OptionalDouble[2.0]
- int max = IntStream.of(1, 2, 3).max().orElse(0);
- // 管道中元素数据最大值 max: 3
- IntSummaryStatistics statistics = IntStream.of(1, 2, 3).summaryStatistics();
- // 全面的统计结果 statistics: IntSummaryStatistics{count=3, sum=6, min=1, average=2.000000, max=3}
期待您的关注
博主最近新写了一本书:《手摸手教您学习 SpringBoot 系列 - 16 章 97 节》 http://springboot.zimug.com/
来源: https://www.cnblogs.com/zimug/p/11839517.html