Functional Programming in Java venkat(16) Being Lazy part3

news/2024/5/3 12:11:33/文章来源:https://blog.csdn.net/shizheng_Li/article/details/128120938

文章目录

  • Functional Programming in Java venkat(16): Being Lazy
    • Leveraging the Laziness of Streams
      • Intermediate and Terminal Operations
      • Method Evaluation Order
      • Peeking into the Laziness

Functional Programming in Java venkat(16): Being Lazy

这里是记录学习这本书 Functional Programming in Java: Harnessing the Power Of Java 8 Lambda Expressions 的读书笔记,如有侵权,请联系删除。

Leveraging the Laziness of Streams

Leveraging the Laziness of Streams

好处

可以推迟一连串的求值,这样每次只有逻辑中最重要的部分被求值

The lazy evaluation of Streams is quite powerful. First, we don’t have to do anything special to derive their benefits. In fact, we’ve used them many times already! Second, they can postpone not just one, but a sequence of evaluations so that only the most essential parts of the logic are evaluated, and only when needed.

Intermediate and Terminal Operations

中间业务和终点站业务(终端操作):

laziness背后的秘密是,把多个中间操作连在一起,然后再进行终端操作。

The secret behind their laziness is that we chain multiple intermediate
operations followed by a terminal operation.

像map()和filter()这样的方法是中间性的;对它们的调用会立即返回,提供给它们的lambda表达式不会立即被评估。这些方法的核心行为被缓存起来,以便以后执行,当它们被调用时,没有真正的工作被完成。

只有当终端操作之一,如findFirst()和reduce(),被调用时,缓存的核心行为才会被执行,但只足以产生所需的结果。

Methods like map() and filter() are intermediate; calls to them return immediately and the lambda expressions provided to them are not evaluated right away. The core behavior of these methods is cached for later execution and no real work is done when they’re called. Only when one of the terminal operations, like findFirst() and reduce(), is called are the cached core behaviors executed, but only enough to produce the desired result.

假设我们得到了一组名字,并被要求用大写字母打印第一个只有三个字母长的名字。

Suppose we’re given a collection of names and are asked to print in all caps the first name that is only three letters long.

两个需要的方法,求名字长度和变成大写

  private static int length(final String name) {System.out.println("getting length for " + name);return name.length();}private static String toUpper(final String name ) {System.out.println("converting to uppercase: " + name);return name.toUpperCase();}

下面这一段代码干了啥呢?

我们从一个人名列表开始,将其转化为Stream,只过滤掉长度为三个字母的人名,将选定的人名转化为全大写,然后从这组人名中挑选第一个人名。

We started with a list of names, transformed it into a Stream, filtered out only names that are three letters long, converted the selected names to all caps, and picked the first name from that set.

public static void main(final String[] args) {List<String> names = Arrays.asList("Brad", "Kate", "Kim", "Jack", "Joe","Mike", "Susan", "George", "Robert", "Julia", "Parker", "Benson");System.out.println("//" + "START:CHAIN_OUTPUT");{final String firstNameWith3Letters = names.stream().filter(name -> length(name) == 3).map(name -> toUpper(name)).findFirst().get();System.out.println(firstNameWith3Letters);}System.out.println("//" + "END:CHAIN_OUTPUT");}

Method Evaluation Order

从右到左,或从下往上阅读代码,会有助于了解这里的真实情况。

调用链中的每一步将只做足够的工作来确保链中的终端操作(terminal operation)完成。

这种行为与通常的急切评估(eager evaluation)直接相反,但却很有效率。

It would help to read the code from right to left, or bottom up, to see what’s really going on here. Each step in the call chain will do only enough work to ensure that the terminal operation in the chain completes. This behavior is in direct contrast to the usual eager evaluation, but is efficient.

如果从前往后看,所需要执行的操作。

image-20221130191610211

如果代码是急切的,filter()方法将首先穿过集合中的所有十几个名字,创建一个两个名字的列表,Kim和Joe,其长度为3(字母)。随后对map()方法的调用就会评估这两个名字。findFirst()方法最后会在这个缩小的列表中挑选出第一个名字。

If the code were eager, the filter() method would have first gone through all dozen names in the collection to create a list of two names, Kim and Joe, whose length is three (letters). The subsequent call to the map() method would have then evaluated the two names. The findFirst() method finally would have picked the first element of this reduced list. We can visualize this hypothetical eager order of evaluation in the next figure.

然而,filter()和map()方法都是懒到骨子里的。在执行过程中,filter()和map()方法会存储lambda表达式,并将一个façade传递给链中的下一个调用。只有当findFirst()这个终端操作被调用时,才开始评估。

However, both the filter() and map() methods are lazy to the bone. As the execution goes through the chain, the filter() and map() methods store the lambda expressions and pass on a façade to the next call in the chain. The evaluations start only when findFirst(), a terminal operation, is called.

评估的顺序也是不同的,正如我们在下图中看到的。

filter()方法并不是一次就把集合中的所有元素都扫一遍。相反,它一直运行到找到第一个满足所附lambda表达式中的条件的元素。一旦找到一个元素,它就会将其传递给链中的下一个方法。

下一个方法,即本例中的map(),在给定的输入上做它的部分,并将其向下传递。

当评估到达终点时,终端操作会检查它是否已经收到了它所寻找的结果。

The order of evaluation is different as well, as we see in the next figure. The filter() method does not plow through all the elements in the collection in one shot. Instead, it runs until it finds the first element that satisfies the condition given in the attached lambda expression. As soon as it finds an element, it passes that to the next method in the chain. This next method, map() in this example, does its part on the given input and passes it down the chain. When the evaluation reaches the end, the terminal operation checks to see if it has received the result it’s looking for.

image-20221130192439130

如果终端操作得到了它所需要的东西,那么该链的计算就终止了。

如果终端操作没有被满足,它将要求对集合中的更多元素进行操作链。

If the terminal operation got what it needed, the computation of the chain terminates. If the terminal operation is not satisfied, it will ask for the chain of operations to be carried out for more elements in the collection.

我们可以运行上述代码,产生我们所期望的结果,只评估了前三个名字:

//START:CHAIN_OUTPUT
getting length for Brad
getting length for Kate
getting length for Kim
converting to uppercase: Kim
KIM
//END:CHAIN_OUTPUT

我们在前面的例子中看到的逻辑操作顺序是在JDK中通过融合操作(fusing operation)实现的–所有中间操作的方法都被融合成一个方法,这个方法对每个元素进行适当的评估,直到终端操作(terminal operation)得到满足。

从本质上讲,对数据只有一次传递–过滤、映射和选择元素都是一次性完成的。

The logical sequence of operations we saw in the previous example is achieved under the hood in the JDK using a fusing operation—all the functions in the intermediate operations are fused together into one function that is evaluated for each element, as appropriate, until the terminal operation is satisfied. In essence, there’s only one pass on the data—filtering, mapping, and selecting the element all happen in one shot.

Peeking into the Laziness

我们把filter,map放在一起,而把终端操作findFirst单独放在后面。

 System.out.println("//" + "START:SPLIT_OUTPUT");{Stream<String> namesWith3Letters = names.stream().filter(name -> length(name) == 3).map(name -> toUpper(name));System.out.println("Stream created, filtered, mapped...");System.out.println("ready to call findFirst...");final String firstNameWith3Letters =namesWith3Letters.findFirst().get();System.out.println(firstNameWith3Letters);}System.out.println("//" + "END:SPLIT_OUTPUT");

输出结果

//START:SPLIT_OUTPUT
Stream created, filtered, mapped...
ready to call findFirst...
getting length for Brad
getting length for Kate
getting length for Kim
converting to uppercase: Kim
KIM
//END:SPLIT_OUTPUT

从输出中我们可以清楚地看到,中间操作将其真正的工作推迟到最后一个负责任的时刻,即调用终端操作的时候。即使如此,它们也只做了满足终端操作所需的最小工作。

From the output we can clearly see that the intermediate operations delayed their real work until the last responsible moment, when the terminal operation was invoked. And even then, they only did the minimum work necessary to satisfy the terminal operation.

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

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

相关文章

JavaScript的Web api接口

JavaScript的Web api 文章目录JavaScript的Web api选中元素事件操作元素获取/元素内容获取/修改元素属性获取/修改表单元素属性实现一个显示/隐藏 密码的功能实现一个加减计算器复选框全选/全不选获取/修改样式属性点击文字放大字体实现白天模式与夜间模式的切换操作节点新增节…

02_openstack私有云部署

目录 一、环境准备 1、准备服务器 2、主机名与域名配置 3、yum仓库配置 4、配置时间同步 二、安装Openstack与Nova依赖环境 1、Nova依赖软件包安装 2、Openstack依赖软件包安装 三、搭建私有云 1、环境检查 2、配置应答文件answer.ini 一、环境准备 1、准备服务器 …

Metabase学习教程:仪表盘-8

仪表板中的Markdown很有趣 如何在仪表板中使用Markdown以获得乐趣和有益。 开发有效仪表板通常包括为人们提供上下文&#xff0c;让他们了解计算是如何存在或为什么存在的。虽然精确的标题、描述和带标签的轴可以在很大程度上澄清可视化&#xff0c;但Metabase还允许您向仪表…

Python矩阵乘法 二重循环实现 + 列表推式

这是python 矩阵乘法的简单例子 col 2 row 2 a [[1, 2], [3, 4]] b [[5, 6], [7, 8]] c [[0, 0], [0, 0]] “”" a b c 二维矩阵初始化 c [[0 for col in range(col)] for row in range(row)] a [[0 for col in range(col)] for row in range(row)] b [[0 for c…

2022最新鸽哒IM即时通讯系统源码 带安卓、苹果、PC端(全开源)+部署教程

提示&#xff1a;即时通讯&#xff0c;纯原生开发&#xff0c;各种功能应有尽有 内容目录一、详细介绍二、效果展示1.部分代码2.效果图展示三、学习资料下载一、详细介绍 提示&#xff1a;即时通讯&#xff0c;纯原生开发&#xff0c;各种功能应有尽有 鸽哒是一款类似于v的即时…

有序数组转换为二叉查找树

问题描述 给定一个整数数组&#xff0c;其元素为先序排列&#xff0c;将其转换为高度平衡的二叉查找树。 示例 示例1 Input: nums [-10,-3,0,5,9] Output: [0,-3,9,-10,null,5] Explanation: [0,-10,5,null,-3,null,9] is also accepted: 示例2 Input: nums [1,3] Output: …

Web3.0带来天翻地覆的变化?全面科普!所谓的Web3.0到底是什么?

Web3.0在2021年尾声突然蹿红&#xff0c;在美国国会的听证会里&#xff0c;一句“我们如何确保web3革命发生在美国”引发了大家对于Web3.0的关注&#xff0c;而后马斯克一篇内容为“有人看过web3.0吗? 我没有找到”的推文&#xff0c;将关于Web3.0的讨论推向了高潮。 甚至于这…

Scala集合习题001

熟话说的好&#xff1a;”纸上得来终觉浅&#xff0c;绝知此事要躬行“&#xff0c;所以现在我就以下的习题&#xff0c;来巩固 之前我学习的几个常见集合函数&#xff0c;加深理解。 目录 练习题 1&#xff1a;计算分组后的list 分别对应的长度&#xff0c;和累加值 练习题…

eMagin:当月产百万片时,4K MicroOLED成本将不是问题

在今年2022 SID显示周期间&#xff0c;Micro OLED微显示模组厂商eMagin曾展示一款专为超短焦VR头显开发的4K Micro OLED微显示屏&#xff0c;有趣的是&#xff0c;该显示屏连接的主板上印有STEAMBOAT字样&#xff0c;让人不禁怀疑它与Valve之间是否存在某种联系。甚至有猜测认为…

Vue 3的高颜值UI组件库

Vue 3.0 已经发布两年多的时间&#xff0c;今年 2 月 Vue 3.0 也正式成为新的默认版本。今天就来分享 7 个适用于 Vue 3 的高颜值 UI 组件库&#xff01; Element Plus Element Plus 是一套由饿了么开源出品的为开发者、设计师和产品经理准备的基于 Vue 3.0 的组件库。Elemen…

xcode swift 单元测试 test

XCTest是苹果官方的测试框架&#xff0c;是基于OCUnit的传统测试框架&#xff0c;测试编写起来非常简单。 测试案例一 创建一个单元测试 func testExample() throws {let personID:String "0123456789"let count personID.countXCTAssert(count < 10, "I…

分布式文件系统

0.0 分布式文件系统 一般做法&#xff1a; 传统的模式是我们通过tomcat或者nginx&#xff0c;存放静态资源文件。 存在的问题&#xff1a; 单个节点会出现存不下的情况&#xff0c;需要多个节点。 分布式文件系统 需要一个系统来管理多个计算机节点上的文件数据&#xff…

[附源码]计算机毕业设计springboot基于web的建设科技项目申报管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

word 中添加图片目录、内部链接

目录1. 图片、表格添加目录1.1 插入题注1.2 添加目录2. 添加内部链接1. 图片、表格添加目录 1.1 插入题注 只有正确地插入题注&#xff0c;图表目录才能快速生成。 &#xff08;1&#xff09;两个方法调用“题注”功能&#xff08;任选1个&#xff09; 方法一&#xff1a;在菜…

[附源码]SSM计算机毕业设计医院挂号系统JAVA

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

Oracle表空间详细介绍

表空间概述 Oracle的表空间属于Oracle中的存储结构&#xff0c;是一种用于存储数据库对象(如&#xff1a;数据文件)的逻辑空间&#xff0c;是Oracle中信息存储的最大逻辑单元&#xff0c;其下还包含有段、区、数据块等逻辑数据类型。表空间是在数据库中开辟的一个空间&#xf…

Cpp知识点系列-字符串

前言 记录一些对字符串的理解。 接下来我所说的都是依赖于头文件<string>的。 理论 什么是字符串 字符串实际上是使用 null 字符 \0 终止的一维字符数组。因此&#xff0c;一个以 null 结尾的字符串&#xff0c;包含了组成字符串的字符。 string与cstring有什么区别…

Linux多线程C++版(七) 线程互斥方式-----读写锁

目录1.读写锁基本概念2.读写锁创建和销毁3.读写锁的加锁和解锁4.代码了解读写锁5.线程互斥案例---ATM取钱--使用读写锁1.读写锁基本概念 线程使用互斥锁缺乏读并发性当读操作比较多&#xff0c;写操作比较少时&#xff0c;可使用读写锁提高线程读并发性读写锁数据类型 pthread…

专访D-Wave CEO:量子计算的过去、现在和未来

&#xff08;图片来源&#xff1a;网络&#xff09; 量子计算可能成为一项颠覆性技术&#xff1a;它建立在听起来非常奇特的物理学基础上&#xff0c;并有望以前所未有的速度和效率解决某些类别的问题。一些人认为&#xff0c;目前在量子计算领域的承诺太多&#xff0c;交付却不…

FPGA书籍

1、Xilinx FPGA 权威设计指南 本书系统地介绍了Xilinx新一代集成开发环境Vivado 2018的设计方法、设计流程和具体实现。 全书共11章&#xff0c;内容包括Xilinx新一代UltraScale结构、Vivado集成设计环境导论、Vivado工程模式基本设计实现、Vivado非工程模式基本设计实现、创建…