Functional Programming in Java venkat(16) Being Lazy part3
创始人
2024-03-03 16:04:51

文章目录

  • 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 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 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.

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...