java - Sorted() 和 concat() 的奇怪流行为

标签 java java-stream lazy-evaluation short-circuiting

流评估通常是惰性的(默认情况下),除非有状态操作作为管道的一部分存在。我遇到了由于有状态操作而违反惰性的情况,我不明白为什么会发生这种情况。

考虑以下代码:

List<Integer> l1 = List.of(4, 5, 3, 1, 2);
List<Integer> l2 = List.of(6, 7, 8, 9, 10);

Stream
    .concat(
        l1.stream()
            .map(i -> {
                System.out.println("in the map for " + i);
                if (i % 3 != 0) {
                    return null;
                }
                return i;
            }),
        l2.stream())
    .filter(i -> {
        System.out.println("in the filter " + i);
        return i != null;
    })
    .findAny();

详细信息:

我有两个由整数列表构造的流( l1l2 )。两个流连接起来形成一个新流。

l1流经过一些映射,将每个不能被 3 整除的项转换为 null ; l2流按原样获取。在串联流上,我添加一个过滤器(仅过滤非空值 --> 因此,从第一个流开始,只有划分为 3 的项目才会通过管道),最后是终端操作 findAny这会触发流的管道(并且将有效地传回第一个可被 3 整除的项目并停止流处理)。

此代码按预期工作:首先 l1元素在 l2 之前被消耗已达到项目。输出显示 l1 如何调用映射函数,然后调用前两个 l1 的串联流过滤器函数项,当 l1 的第 3 项时,整个流完成。不会转换为 null,因此在过滤器中仍然存在:

in the map for 4
in the filter null
in the map for 5
in the filter null
in the map for 3
in the filter 3

问题(或者我不明白的事情)开始于 l1流被修改为 .sorted操作:

Stream
    .concat(
        l1.stream()
            .sorted()
            .map(i -> {
                System.out.println("in the map for " + i);
                if (i % 3 != 0) {
                    return null;
                }
                return i;
            }),
        l2.stream())
    .filter(i -> {
        System.out.println("in the filter " + i);
        return i != null;
    })
    .findAny();

...现在情况看起来有所不同:

in the map for 1
in the map for 2
in the map for 3
in the map for 4
in the map for 5
in the filter null
in the filter null
in the filter 3

由于sorted是有状态操作,我知道它首先需要消耗整个l1流对其值进行排序。让我惊讶的是,它似乎也影响了 l1 的其余部分。管道为map与之前一样,在任何串联流过滤器方法调用之前急切调用函数。

我读到Java Streams - Buffering huge streamsWhy filter() after flatMap() is "not completely" lazy in Java streams? ,并且我已经在 java 17 上运行并使用 Stream.concat()我没有使用 flatMap() (至少没有明确)。

你能解释一下为什么吗?我在这里缺少什么?

最佳答案

这是由 JDK-8277306: stream with sorted() and concat() causes some ops not to be lazy 引起的,已关闭为“不会修复”,并附有以下评论:

Stream.concat takes the spliterator from each input stream and combines them to create a new spliterator from which a new stream is constructed. Thereby it binds to the sources of each stream to concatenate.

It is currently not possible propagate the short circuiting property of the stream pipeline after the concatenation to pipeline before the concatenation. It comes down to resolving the push vs. pull differences across the spliterator boundary. That's a tricky problem, and one that Ilikely requires significant effort that I find hard to justify given the scope of the problem.

关于java - Sorted() 和 concat() 的奇怪流行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75221416/

相关文章:

jquery - 如何剪切背景图像以正确延迟加载?

java - 在 json 的列表字段中显示数据和图像,就像延迟加载黑莓一样

java - 在 Mockito 中有什么方法可以设置规则以在调用特定对象类型的属性时返回值?

c# - RSA 和 PublicKey 与 dotnet 的互操作

JavaFX - ReadOnlyProperty 不是只读的

java - 如何使用流在不阻塞的情况下处理队列的所有元素?

java - 使用 Java Stream API 在 map 中查找重复值

java - 如何从两个不同对象的列表中获取不常见的对象

java - : org. glassfish.tyrus.spi.ClientContainer 引起的错误

haskell - Haskell 中这个循环链表上的 "tying the knot"是如何工作的?