当前位置: 首页 > 知识库问答 >
问题:

Java中间操作何时命中每个元素?

长孙瑞
2023-03-14

我对Java流的工作方式感到困惑,特别是在短路方面。举一个让我困惑的例子,我虚构了以下例子:

List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
Optional<Integer> res = list.stream()
        .map(x -> {
            System.out.println("first map: " + x);
            return 2*x;
        })
        .sorted((a,b)-> {
            System.out.println("sorting " + a + " : " + b);
            return a - b;
        })
        .map(x -> {
            System.out.println("second map: " +  x);
            return 2*x;
        })
        .findAny();
System.out.println("found " + res.get());

有输出

first map: 1
first map: 2
first map: 3
first map: 4
first map: 5
first map: 6
first map: 7
first map: 8
first map: 9
first map: 10
sorting 4 : 2
sorting 6 : 4
sorting 8 : 6
sorting 10 : 8
sorting 12 : 10
sorting 14 : 12
sorting 16 : 14
sorting 18 : 16
sorting 20 : 18
second map: 2
found 4

执行时,该代码演示了调用<代码>排序的中间,强制第一个映射应用于流中的每个元素。但是,第二个映射不会应用于流中的每个元素,因为findAny会使其短路。

所以基本上我的问题是:这里的规则是什么?为什么Java足够聪明,知道它不需要对流的每个元素调用第二个映射,但不足够聪明,知道最后的findAny不需要它实际排序任何东西。

我试着“阅读手册”,但我不清楚。

共有1个答案

曹新觉
2023-03-14

发生这种情况是因为流正在懒惰地一次一个地处理来自源的元素。

每个操作仅在需要时发生。

在排序的情况下,流将所有数据从源转储到内存,因为没有办法一个接一个地对元素进行排序。

map --> sorted --> map --> findAny

第一次映射操作应用于所有元素,因为它先于排序操作。

排序完成后,将一次处理一个元素。

findAny是一种短路操作。因此,终端操作将窥视第一个元素,第二个映射操作仅应用一次。

为什么Java足够聪明,不需要在流的每个元素上调用第二个映射,但却不足够聪明,不需要findAny在最后对任何内容进行实际排序

好吧,我猜是因为直到现在单线程执行中的findAny()的行为仍然与findFirst()完全相同,它需要进行排序才能找到正确的结果。

您可以尝试使用sequential stream,发现findAny()和findFirst()会产生相同的结果。

我不能给你答案,为什么它的行为如此远离。

Java文档谨慎地说findAny()

此操作的行为显然是不确定的

但实际上,对于有序的数据源,它在顺序流的情况下仍然是可预测的,而在并行流的情况下则是不确定的。

https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/stream/Stream.html

 类似资料:
  • 给定一个数字字符串,我想在字符串中的每n位数应用一个操作。这可能与java流? 例如,对于字符串,并对每2个字符应用3的和,结果将是。 上面的结果是,因为总和应用于所有字符。

  • 我是Java的新手。我有一个时间是从网页上得到的,这是“hh:mm”格式(不是 24 小时)。这对我来说就像一个字符串。然后,我想将此字符串与今天的日期组合在一起,以便制作一个可以使用的 Java 。 在 C# 中: 在Java中,我尝试过: 有没有更好的方法来实现我想要的?

  • 问题内容: 我想使用Python比较列表中的每个可能的对。 假设我有 我想对列表中2个元素的每个组合进行操作(我们称其为foo)。 最终结果应与 我的第一个想法是手动遍历列表两次,但这似乎不是很Python。 问题答案: 在模块中签出。它完全符合您的描述。 这等效于: 编辑: 有两个非常相似的功能,以及,和。为了说明它们之间的区别: 生成所有可能的元素对,包括所有重复项: 生成每个唯一元素对的所有

  • 问题内容: 我在python中有一个字符串元素列表,想用来编辑元素中的每个元素,所以我有一个新元素。请参见下面的代码(它不起作用,但是您会明白的): 有没有办法做到这一点? 问题答案:

  • 本文向大家介绍Java 8中的中间操作和终端操作之间的区别,包括了Java 8中的中间操作和终端操作之间的区别的使用技巧和注意事项,需要的朋友参考一下 在Java 8中引入了Stream,它仅用于处理数据组而不用于存储元素。它不修改实际的集合,它们仅根据流水线方法提供结果。 Stream api支持多种操作,并且操作分为两部分- 中间操作—这些操作用于管道化其他方法并转换为其他流。它们不会产生结果

  • 我需要在K8S中管理部署的建议。我需要使用gitops进行蓝色/绿色部署,这基本上给我留下了两个选择: 这将需要使用helm来管理删除资源等等,并通过helm通过代理管理blue/green,而这又将需要创建重复的部署模板(用于green和blue)。 优点:由掌舵人管理,会删除已删除的资源;似乎是一般的做法。 缺点:由helm管理,可能会搞砸一些东西,特别是在多个失败的部署中;可以创建雪花命名空