成为Java流大师–第3部分:终端操作

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

本文是五分之三,以GitHub存储库为补充,其中包含每个单元的说明和练习。
第1部分:创建流
第2部分:中级操作 第三部分:终端操作 第4部分:数据库流 第5部分:使用流创建数据库应用程序

终端机操作

现在我们熟悉Stream管道的初始化和构造,我们需要一种处理输出的方法。 终端操作通过从其余元素(例如
count() )或副作用(例如
forEach(Consumer) )。

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

让我们看一下可以应用于Stream管道末尾的哪些终端操作:

ForEach和ForEachOrdered

流的可能用例可能是更新某些或所有元素的属性,或者为什么不只是出于调试目的而将它们打印出来。 无论哪种方式,我们都不希望收集或计数输出,而是通过产生副作用而不返回值来进行。

这是目的
forEach()
forEachOrdered() 。 他们俩都 Consumer并终止Stream,而不返回任何内容。 这些操作之间的区别仅仅是 forEachOrdered()承诺按照元素在Stream中出现的顺序调用提供的Consumer。 forEach()仅承诺以任何顺序调用Consumer。 后一种变体对并行流很有用。

在下面的简单情况下,我们在一行中打印出Stream的每个元素。

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

这将产生以下输出:

 MonkeyLionGiraffeLemurLion 
 <br> 

收集元素

Streams的常见用法是构建元素的“存储桶”,或更具体地说,构建包含特定元素集合的数据结构。 这可以通过调用终端操作来完成
Stream末尾的collect() ,因此要求它将元素收集到给定的数据结构中。 我们可以提供称为
Collector collect()操作,可以根据手头的问题使用许多不同的预定义类型。 以下是一些非常有用的选项:

收集到设置

我们可以将所有元素收集到
通过使用收集器收集Stream的元素来简单地进行Set
toSet()

 Set<String> collectToSet = Stream.of( "Monkey" , "Lion" , "Giraffe" , "Lemur" , "Lion"  ) .collect(Collectors.toSet()); 
 toSet: [Monkey, Lion, Giraffe, Lemur] 

收集到清单

同样,可以将元素收集到
List使用
toList()收集器。

 List<String> collectToList = Stream.of( "Monkey" , "Lion" , "Giraffe" , "Lemur" , "Lion"  ) .collect(Collectors.toList()); 
 collectToList: [Monkey, Lion, Giraffe, Lemur, Lion] 

收集到一般收藏

在更一般的情况下,可以将Stream的元素收集到任何
通过仅提供所需构造函数的Collection
Collection类型。 构造函数的例子是 LinkedList::newLinkedHashSet::newPriorityQueue::new

 LinkedList<String> collectToCollection = Stream.of( "Monkey" , "Lion" , "Giraffe" , "Lemur" , "Lion"  ) .collect(Collectors.toCollection(LinkedList:: new )); 
 collectToCollection: [Monkey, Lion, Giraffe, Lemur, Lion] 

收集到阵列

由于数组是固定大小的容器,而不是灵活的容器 Collection ,有充分的理由进行特殊的终端操作, toArray() ,以将元素创建并存储在Array中。 请注意,仅调用toArray()会导致Objects Array ,因为该方法无法自行创建类型化数组。 下面我们展示如何使用String数组的构造函数来提供类型化的数组String[]

 String[] toArray = Stream.of( "Monkey" , "Lion" , "Giraffe" , "Lemur" , "Lion"  ) .toArray(String[]:: new ); 
 toArray: [Monkey, Lion, Giraffe, Lemur, Lion] 

收集到地图

我们可能想从元素中提取信息,并将结果提供为Map 。 为此,我们使用收集器toMap() ,它需要两个
Functions按键对应的映射器和值映射器。

该示例显示了不同的动物如何与它们名称中不同字符的数量相关联。 我们使用中间操作distinct()来确保仅在Map添加唯一键(如果键不是唯一的,则必须提供toMap()收集器的变体,其中必须提供用于合并的解析器来自相等键的结果)。

 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 )); 
 toMap: {Monkey= 6 , Lion= 4 , Lemur= 5 , Giraffe= 6 }  (*) 

(*)请注意,键顺序是未定义的。

收集分组

坚持使用桶的类比,我们实际上可以同时处理多个桶。 有一个非常有用的Collector名为
groupingBy()根据某些属性将元素划分为不同的组,从而通过称为“分类器”的某种内容提取该属性。 这样的操作的输出是Map 。 下面我们演示如何根据动物的名字的首字母对动物进行分组。

 Map<Character, List<String>> groupingByList = Stream.of( "Monkey" , "Lion" , "Giraffe" , "Lemur" , "Lion"  ) .collect(Collectors.groupingBy( s -> s.charAt( 0 ) // Function<String, K> classifier )); 
 groupingByList: {G=[Giraffe], L=[Lion, Lemur, Lion], M=[Monkey]} 

使用下游收集器收集分组

在前面的示例中,默认情况下,将“下游收集器” toList()应用于Map的值,将每个存储桶的元素收集到List 。 有一个重载版本的groupingBy() ,它允许使用自定义的“下游收集器”来更好地控制生成的Map 。 下面是一个示例,说明如何将特殊的下游收集器counting()用于计数(而不是收集)每个存储区的元素。

 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 )); 
 groupingByCounting: {G= 1 , L= 3 , M= 1 } 

这是该过程的说明:

任何收集器都可以用作下游收集器。 特别是,值得注意的是,收集器groupingBy()可以采用下游收集器,该下游收集器也是groupingBy()收集器,从而允许对第一分组操作的结果进行二次分组。 在我们的动物案例中,我们也许可以创建一个Map<Character, Map<Character, Long>> ,其中第一个地图包含具有第一个字符的键,第二个地图包含第二个字符作为键,出现次数作为值。

元素的出现

中间操作filter()是消除与给定谓词不匹配的元素的好方法。 尽管在某些情况下,我们只是想知道是否存在至少一个满足该谓词的元素。 如果是这样,使用anyMatch()会更方便和有效。 在这里,我们寻找数字2的出现:

 boolean containsTwo = IntStream.of( 1 , 2 , 3 ).anyMatch(i -> i == 2 ); 
 containsTwo: true 

计算操作

几个终端操作输出计算结果。 我们可以执行的最简单的计算是count() ,它可以应用于任何
Stream. 例如,它可以用于计算动物数量:

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

虽然,某些终端操作仅适用于我们在第一篇文章中提到的特殊Stream实现。 IntStream
LongStreamDoubleStream 。 可以访问此类流,我们可以简单地将所有元素汇总如下:

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

或者为什么不使用.average()计算整数的平均值:

 OptionalDouble average = IntStream.of( 1 , 2 , 3 ).average(); 
 average: OptionalDouble[ 2.0 ] 

或使用.max()检索最大值。

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

average()一样, max()运算符的结果是Optional ,因此通过声明.orElse(0)我们自动检索该值(如果存在或默认为0)。 如果我们宁愿处理原始返回类型,也可以将相同的解决方案应用于平均示例。

如果我们对所有这些统计数据都感兴趣,那么创建几个相同的流并对每个流应用不同的终端操作是非常麻烦的。 幸运的是,有一个方便的操作称为summaryStatistics() ,它允许将几个常见的统计属性合并到一个
SummaryStatistics对象。

 IntSummaryStatistics statistics = IntStream.of( 1 , 2 , 3 ).summaryStatistics(); 
 statistics: IntSummaryStatistics{count= 3 , sum= 6 , min= 1 , average= 2.000000 , max= 3 } 

练习题

希望您现在熟悉所提供练习的格式。 如果您只是发现了该系列或者最近才感到有点懒惰(也许您也有自己的理由),我们建议您克隆GitHub存储库并开始使用后续材料。 本文的内容足以解决名为MyUnit3Terminal的第三个单元。 相应的Unit3Terminal接口包含JavaDocs,它们描述MyUnit3Terminal方法的预期实现。

 public interface Unit3Terminal { /** * Adds each element in the provided Stream * to the provided Set. * * An input stream of ["A", "B", "C"] and an * empty input Set will modify the input Set * to contain : ["A", "B", "C"] * * @param stream with input elements * @param set to add elements to */  void addToSet(Stream stream, Set set); 
 <br> 

提供的测试(例如Unit3MyTerminalTest)将充当自动评分工具,让您知道您的解决方案是否正确。

下一篇

下一篇文章将展示如何将到目前为止我们积累的所有知识应用于数据库查询。

提示:再见SQL,Hello Streams…直到那时–编码愉快!

s

Per Minborg

Julia·古斯塔夫森(Julia Gustafsson)

翻译自: https://www.javacodegeeks.com/2019/10/become-master-java-streams-terminal-operations.html

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

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

相关文章

python选项卡中文详细说明_pycharm窗口选项卡管理

1、主题我们已经注意到Pycharm的主编辑框是基于窗口选项卡机制显示的&#xff0c;Pycharm选项卡多种多样&#xff0c;这里我们将详细介绍这种选项卡机制。2、激活的选项卡每当我们打开一个Python文件时open a file for editing&#xff0c;它都会对应打开一个选项卡窗口&#x…

和至少为k的最短子数组 python_和至少为k的最短子数组

// 单调栈// 维护一个具有栈单调性的队列&#xff0c;跟动态规划不一样的是时间复杂度为O(n)// queue[i]中存放着前缀和// 我们知道因为负数的存在&#xff0c;所以队列不是单调增长的&#xff0c;但是不单调的其实对我们没有用// 因为肯定可以找到比它短的(因此我们移除比)// …

matlab多径信道模型,基于matlab的无线多径信道建模与仿真分析

基于matlab的无线多径信道建模与仿真分析 基于MATLAB的无线多径信道建模与仿真分析 摘 要:对于无线通信, 衰落是影响系统性能的重要因素, 而不同形式的衰落对于信号产生的影响 也不相同。本文在阐述移动多径信道特性的基础上, 建立了不同信道模型下多径时延效应的计算 机仿真模…

c 遍历文件 递归遍历_将递归文件系统遍历转换为流

c 遍历文件 递归遍历在学习编程的时候&#xff0c;回溯到Turbo Pascal的时代&#xff0c;我设法使用FindFirst &#xff0c; FindNext和FindClose函数在目录中列出文件。 首先&#xff0c;我想出了一个打印给定目录内容的过程。 您可以想象我为能够真正从自身调用该过程以递归遍…

净迁移人口预测程序python_高质量深度学习模型, 一键模型预测,迁移学习很简单...

飞桨(PaddlePaddle)核心框架Paddle Fluid v1.5已经发布&#xff0c;而作为其关键工具&#xff0c;用来迁移学习的PaddleHub也进行了全面更新&#xff0c;正式发布了1.0版本。全新的PaddleHub模型和任务更加丰富&#xff0c;为用户提供了覆盖 文本 、 图像 和 视频 三大领域八大…

您的JVM是否泄漏文件描述符-像我的一样?

前言&#xff1a;此处描述的两个问题是在一年前发现并修复的。 本文仅用作历史证明&#xff0c;也是有关解决Java中文件描述符泄漏的初学者指南。 在Ultra ESB中&#xff0c;我们使用内存RAM磁盘文件缓存来进行快速且无垃圾的有效负载处理。 一段时间以前&#xff0c;我们在共…

matlab中degrees,Convert degrees-minutes-seconds to degrees

Angle in degrees-minutes-seconds representation, specified as ann-by-3 real-valued matrix. Each row specifies oneangle, with the format [D M S]:D contains the “degrees” elementand must be integer-valued.M contains the “minutes” elementand must be integ…

螺旋桨设计软件_欧洲斥巨资研发的A400M螺旋桨运输机,为啥就没人买啊?| 图说...

A400M是欧洲自行设计、研制和生产的新一代军用运输机&#xff0c;也是欧盟国家进行合作的最大的武器联合研制项目。A400M最大的特点&#xff0c;就是其标志性的8叶弯刀螺旋桨。A400M也是20世纪后服役的为数不多的几个使用涡轮旋桨发动机的军用运输机之一。A400M曾在系列电影《碟…

python5个功能_5个常用的定制Python功能代码

文章来源&#xff1a;淘论文网 发布者&#xff1a;毕业设计浏览量:一、随机数生成>>> import random #导入Python内置的随机模块>>> num random.randint(1,1000) #生成1-1000之间的伪随机数二、读文件>>> f open(c:\1.txt,r)>>> lin…

php链接远程socket,php使用socket获取远程图片

步骤&#xff1a;1&#xff0c;匹配URL中的主机名和文件部分2&#xff0c;创建socket并连接到目标服务器3&#xff0c;构造HTTP请求并发送4&#xff0c;读取HTTP响应并解析5&#xff0c;保存内容到文件并关闭socket连接代码实现如下&#xff1a;/** 使用socket获取远程资源(网页…

JAR文件句柄:烦恼后清理!

在Ultra ESB中&#xff0c;我们使用特殊的热交换类加载器 &#xff0c;该加载器使我们可以按需重新加载Java类。 这使我们能够从字面上热交换我们的部署单元 -加载&#xff0c;卸载&#xff0c;使用更新的类重新加载&#xff0c;以及正常地逐步退出-无需重启JVM。 Windows&…

大气校正后的ndvi_Sentinel2 L1C下载、大气校正、重采样

点击蓝字关注我哦1.基本信息(成像仪/重访周期/波段数/分辨率)哨兵2号是高分辨率多光谱成像卫星&#xff0c;携带一枚多光谱成像仪(MSI)&#xff0c;用于陆地监测&#xff0c;可提供植被、土壤和水覆盖、内陆水路及海岸区域等图像&#xff0c;分为2A和2B两颗卫星,哨兵&#xff0…

hello python的代码,python基础教程之Hello World!

Python命令行假设你已经安装好了Python, 那么在Linux命令行输入:代码如下:$python将直接进入python。然后在命令行提示符>>>后面输入:代码如下:>>>print(Hello World!)可以看到&#xff0c;随后在屏幕上输出:代码如下:Hello World!print是一个常用函数&#…

python3 线程隔离_Python的线程隔离实现方法

前段时间看了下flask的源码&#xff0c;对于这样一个轻量级的web框架是怎样支持多线程的感到非常好奇&#xff0c;于是深入了解了一番。flask是依赖werkeug来实现线程间的隔离的&#xff0c;而werkeug最后又使用到了python的内置模块locals来承载数据&#xff0c;看不如写&…

限定通配符和非限定通配符_为什么我不信任通配符以及为什么我们仍然需要通配符...

限定通配符和非限定通配符在将子类型多态性&#xff08;面向对象&#xff09;与参数多态性&#xff08;泛型&#xff09;相结合的任何编程语言中&#xff0c;都会出现方差问题。 假设我有一个字符串列表&#xff0c;键入List<String> 。 我可以将其传递给接受List<Obj…

php strtotime month bug,处理PHP strtotime的BUG

PHP strtotime的BUG处理最近使用了strtotime结合-1 month, 1 month, next month获取上个月或者下个月的日期&#xff0c;不过刚看到一篇文章&#xff0c;才知道原来使用strtotime直接获取日期还是有点小BUGBUG如日期&#xff1a;$today 2020-12-31;echo date("Y-m-d"…

JMetro版本11.5.11和8.5.11发布

你好 具有新JMetro样式的另一个版本&#xff08;深色和浅色版本&#xff09;&#xff1a; 分割菜单按钮 分割窗格 药丸按钮/分段按钮 调整现有样式和错误修复。 继续阅读以获取详细信息。 分割菜单按钮 以下是一个动画&#xff0c;显示了新的“拆分菜单按钮” JMetro浅色…

python远程连接mysql数据库_MySQL数据库之python mysql远程连接

本文主要向大家介绍了MySQL数据库之python mysql远程连接 &#xff0c;通过具体的内容向大家展现&#xff0c;希望对大家学习MySQL数据库有所帮助。第一步&#xff1a;vim /etc/MySQL/my.cnf找到bind-address 127.0.0.1注释掉这行&#xff0c;如&#xff1a;#bind-address 12…

php100并发cpu告警,多线程并发导致CPU100%的一种原因和解决办法

在用自定义线程池的时候&#xff0c;遇到cpu100%&#xff0c;经过验证后&#xff0c;发现问题来源于我定义的子线程。子线程的主要功能是从任务队列(LinkedBlockingQueue)里面持续拿出任务&#xff0c;并且执行。以下为令CPU100的代码。private class WorkThread extends Threa…

excel离散度图表怎么算_一般人不知道的几个excel制图技巧

原标题&#xff1a;一般人不知道的几个excel制图技巧作者&#xff1a;杜雨 公众号&#xff1a;数据小魔方(datamofang)今天这篇&#xff0c;我专注于Excel的作图规则&#xff0c;深入的研究下Excel由数据源到可视化图表之间的关系是如何对应的&#xff0c;倘若你已经在工作中横…