Kehaw

Java-Stream学习第三步:终端操作


比尔·盖茨曾经说过:“我选择一个懒惰的人去做一件困难的事情,因为一个懒惰的人会找到一种简单的方法来做。”当涉及到信息流时,没有什么比这更真实了。在本文中,你将学习 Stream 如何通过在调用终端操作之前不对源元素执行任何计算来避免不必要的工作,以及源如何只生成最少数量的元素。

终端操作

通过前面的学习,现在我们熟悉了 Stream Pipeline的初始化和中间处理流程,我们需要一种处理输出的方法。终端操作通过类似count()forEach(Consumer)中产生结果来结束 Stream 流程。

在启动终端操作之前,Stream 将不会对源的元素执行任何计算。这意味着仅在需要时才使用源元素,这是避免不必要工作的明智方式。但是这也意味着一旦应用了终端操作,流将被消耗,并且无法再添加其他操作。

forEach 和 forEachOrdered

很多时候我们并不想做具体的操作,只是想打印一下流处理结束后的内容(调试程序的时候会经常用到),因此我们看一下 forEach()forEachOrdered() 函数:

Stream.of(
   "Monkey", "Lion", "Giraffe", "Lemur", Lion
).forEachOrdered(System.out::print);

forEach()forEachOrdered() 唯一不同的地方在于排序方式。

Collection Elements

更多的时候我们是将 Stream 处理好的结果集放置到一个地方(例如一个set)。此时我们可以通过 Stream 的 collect() 函数来进行操作。

To Set 搜集器
Set<String> collectToSet = Stream.of(
   "Monkey", "Lion", "Giraffe", "Lemur", "Lion"
) .collect(Collectors.toSet());
To List 搜集器
List<String> collectToList = Stream.of(
   "Monkey", "Lion", "Giraffe", "Lemur", "Lion"
).collect(Collectors.toList());
To General Collections 搜集器

我们还可以将 Stream 处理的结果写入到各种集合类中,例如:LinkedList::newLinkedHashSet::newPriorityQueue::new:

LinkedList<String> collectToCollection = Stream.of(
   "Monkey", "Lion", "Giraffe", "Lemur", "Lion"
).collect(Collectors.toCollection(LinkedList::new));
To Array 搜集器

Array 数组在平时是需要初始化大小来进行使用的,因此更适合使用 Stream 来进行初始化,因为在这里我们不需要给出一个初始化的数组大小:

String[] toArray = Stream.of(
   "Monkey", "Lion", "Giraffe", "Lemur", "Lion"
).toArray(String[]::new);
To Map 搜集器
Map<String, Integer> toMap = Stream.of(
    "Monkey", "Lion", "Giraffe", "Lemur", "Lion"
).distinct().collect(Collectors.toMap(
       Function.identity(),   //Function<String, K> keyMapper
       s -> (int) s.chars().distinct().count()// Function<String, V> valueMapper
   ));
对结果进行分组

我们可以针对元素的某些属性进行分组操作,这在以往的需求中也随处可见:

Map<Character, List<String>> groupingByList =  Stream.of(
    "Monkey", "Lion", "Giraffe", "Lemur", "Lion"
).collect(Collectors.groupingBy(
       s -> s.charAt(0) // Function<String, K> classifier
   ));
在分组之后进行额外的操作

有时候我们需要在分组之后进行额外的统计操作,我们可以使用 collect() 函数的第二个参数进行此事:

Map<Character, Long> groupingByCounting =  Stream.of(
    "Monkey", "Lion", "Giraffe", "Lemur", "Lion"
).collect(Collectors.groupingBy(
       s -> s.charAt(0), // Function<String, K> classifier
       counting()        // Downstream collector
   ));

针对分组计数的详细操作如图:

通常我们称这种额外操作为”下游搜集器“,而任何搜集器都可以成为下游搜集器。因此我们可以针对结果进行二次分组。

计算结果

计算结果包括了一些简单的计算例如计数、求和等:

下面是针对元素进行计数的方法:

long nrOfAnimals = Stream.of(
    "Monkey", "Lion", "Giraffe", "Lemur"
).count(); 

下面是求和的方法:

int sum = IntStream.of(1, 2, 3).sum();

下面是求平均值的方法:

OptionalDouble average = IntStream.of(1, 2, 3).average();

下面是求最大值的方法:

int max = IntStream.of(1, 2, 3).max().orElse(0);

或者来一个大集合,所有的方法都用:

IntSummaryStatistics statistics = IntStream.of(1, 2, 3).summaryStatistics();

summaryStatistics() 函数将会输出:

statistics: IntSummaryStatistics{count=3, sum=6, min=1, average=2.000000, max=3}
Kehaw

👨‍💻Ke Haw 🇨🇳👨‍👩‍👧‍👦

风吹云散去,夜色好观星
Java | 前端 | 大数据

专注于 Spring Cloud 微服务架构与数据处理,研究一切与Java相关的开发技术,包括一部分前端技术。

目前的工作主要是关于B2B大宗商品在线交易领域的数据处理。如果对本站的部分内容感兴趣,请通过邮件、Twitter联系我🤝。

Fork me on Gitee
基于Spring Security + OAuth2 + JWT 的权限认证(一) Java-Stream学习第四步:数据处理 Java-Stream学习第三步:终端操作 Java-Stream学习第二步:处理流 Java-Stream学习第一步:创建流 Electron使用串口通信 Electron下调用DLL文件 国外SaaS服务供应商都是干什么的:Part1 为什么Kafka会丢失消息 Spring Boot中使用JSR380验证框架
Description lists
Kehaw's blog
Site description
人初做事,如鸡伏卵,不舍而生气渐充;如燕营巢,不息而结构渐牢;如滋培之木,不见其长,有时而大;如有本之泉,不舍昼夜,盈科而后进,放乎四海。
Copyright
© 2014 Copyright Kehaw | All rights reserved.