Functional Programming in Java venkat(16) Being Lazy part3

news2024/11/30 10:44:36

文章目录

  • 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.coloradmin.cn/o/48887.html

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

相关文章

linux权限详解

文章目录1.用户转换1.将普通用户转换成root1.su -2. su2.将root转换为普通用户2.文件的权限1.文件访问者的分类拥有者和other所属组2.rwx的含义3.修改权限第一种修改方式1.拥有者修改2.所属组的修改3.other的修改4.整体修改第二种修改方式666000777使用权限的修改1.拥有者用户的…

[事务]-事务概念/特性/并发问题/传播特性

1. 事务的概念 事务&#xff08;Transaction&#xff09;指的是一个操作序列&#xff0c;该操作序列中的多个操作要么都做&#xff0c;要么都不做&#xff0c;是一个不可分割的工作单位&#xff0c;是数据库环境中的逻辑工作单位&#xff0c;由DBMS中的事务管理子系统负责…

爬虫工作流程、请求与响应原理、requests库讲解

爬虫工作流程、请求与响应原理、requests库讲解 爬虫分类主要分为两大板块 web爬虫&#xff08;浏览器爬虫&#xff09; APP爬虫&#xff08;手机端爬虫&#xff09; 在这两大板块中又可以把爬虫归类为聚焦爬虫和通用爬虫 聚焦爬虫&#xff1a;针对某一个接口&#xff08;ur…

对话框被遮罩层挡住

element-ui 解决方法一&#xff1a; 在el-dialog中写去掉遮罩层 :modal"false" 解决方法二&#xff1a; 在el-dialog中写&#xff08;遮罩层是否插入至 body 元素上&#xff0c;若为 false&#xff0c;则遮罩层会插入至 Dialog 的父元素上&#xff09; :modal-ap…

[附源码]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…

专业硕士招生占比将达到三分之二,那么跟学术硕士有哪些区别?

近年来的研究生招生考试中&#xff0c;专业硕士的招生培养规模正稳步增长。据统计&#xff0c;2009年专业学位硕士招生人数在硕士招生总人数中的占比仅为15.9%&#xff0c;其后在2017年首次超过学硕招生人数&#xff0c;到2020年专硕招生人数占比已超60%。国务院学位委员会、教…

SpringBoot - 集成Actuator(应用信息显示、修改系统日志、增加账号密码登录)

文章目录Actuator概述官网入口支持的埋点信息查询、修改使用访问actuator埋点信息添加账号密码登录验证动态修改日志级别Actuator 概述 官网入口 官网&#xff1a; https://docs.spring.io/spring-boot/docs/2.7.6/reference/html/actuator.html#actuator.endpoints 支持的埋…

csdn中书写数学公式简单介绍

参考&#xff1a;https://www.zybuluo.com/codeep/note/163962#3%E5%9C%A8%E5%AD%97%E7%AC%A6%E9%97%B4%E5%8A%A0%E5%85%A5%E7%A9%BA%E6%A0%BC 常识、常用 一行公式使用$$开始和结尾&#xff0c;常用符号表示 符号功能$$多行公式的开始和结尾&#xff0c;一个$表示单行公式开…

Cisco ASA基础——安全算法与基本配置

作者简介&#xff1a;一名在校云计算网络运维学生、每天分享网络运维的学习经验、和学习笔记。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​​ 目录 前言 本章重点 一.Cisco防火墙简介 1.什么是防火墙 2.防火墙的作用…

PHP表单处理的案例分析

目录 知识补充 实现过程 前端代码 后端代码 简单分析 知识补充 表单简介&#xff08;来自Mr._Dang&#xff09; action&#xff1a;提交的地址 method&#xff1a;提交的方式 get&#xff1a; 参数是在url中的&#xff0c;不安全&#xff0c;传输量比较少&#xff…

[附源码]Python计算机毕业设计Django的在线作业批改系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

[附源码]Python计算机毕业设计SSM力高灯饰线上交易平台(程序+LW)

项目运行 环境配置&#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…

一言不合就重构

hello&#xff0c;大家好呀&#xff0c;我是小楼。 前段时间不是在忙么&#xff0c;忙的内容之一就是花了点时间重构了一个服务的健康检查组件&#xff0c;目前已经慢慢在灰度线上&#xff0c;本文就来分享下这次重构之旅&#xff0c;也算作个总结吧。 背景 服务健康检查简介…

短视频创作,变现的建议、变现方式和举例,建议收藏反复阅读-上

先说今天的纲要&#xff0c;有兴趣可以继续看下去&#xff0c;今天主要针对短视频变现这件事的讨论&#xff0c;有三个建议&#xff0c;①变现标准低、②变现天花板高、③可主动变现。 我们在选择变现形式的时候&#xff0c;尽可能满足这三个条件或其中两个。 中间我们再讨论下…

【LeetCode】895.最大频率栈

题目描述 设计一个类似堆栈的数据结构&#xff0c;将元素推入堆栈&#xff0c;并从堆栈中弹出出现频率最高的元素。 实现 FreqStack 类: FreqStack() 构造一个空的堆栈。void push(int val) 将一个整数 val 压入栈顶。int pop() 删除并返回堆栈中出现频率最高的元素。 如果出现…

【问题思考总结】NAT的公有地址怎么转换为私有地址?【MAC地址和IP地址的转换】

问题起源 在做一道题的时候&#xff0c;涉及到了由内网到外网再到内网时的IP地址转换。在外网的时候&#xff0c;答案说的是不能够用私有IP地址作为源IP地址&#xff0c;然后疑问产生了&#xff1a;如果不能用私有IP地址作为目的地址&#xff0c;他又怎么能够找到那个主机呢&a…

[附源码]Python计算机毕业设计SSM乐多多宠物店网站(程序+LW)

项目运行 环境配置&#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…

2022年11月30日 Fuzzy C-Means学习笔记

​ Fuzzy C-Means 模糊c均值聚类&#xff0c;它的一大优势就是引入了一个隶属度的概念&#xff0c;没有对样本进行非黑即白的分类&#xff0c;而是分类的时候乘上隶属度&#xff0c;直白点说就是他和某个中心有多像&#xff0c;到底是40%像还是70%像。 ​ 参考&#xff1a;在众…

CF27E (2000) (反素数)

https://codeforces.com/contest/27/problem/E 反素数&#xff1a; 若N < 2 ^ 31 引理1&#xff1a; 1 ~ N 中的反素数&#xff0c;就是 1 ~ N中约数个数最多的数中 最小 的一个。 引理2&#xff1a; 1 ~ N 中任何数的不同质因子都不会超过 10 个且所有质因子的质数都不会超…

真题集P91---2018年计专真题

真题集P91---2018年计专真题三(2)自由树直径思路代码四思路代码五思路代码三(2)自由树直径 思路 1、吉大出的题目&#xff0c;没规定是否是有权图&#xff0c;以及是否是有向图&#xff0c;所以这里默认&#xff0c;权值是1的无向图。 1、如果权值都一样&#xff0c;用邻接表存…