首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >为什么flatMap()之后的filter()在Java stream中是“不完全”惰性的?

为什么flatMap()之后的filter()在Java stream中是“不完全”惰性的?
EN

Stack Overflow用户
提问于 2015-03-24 17:46:54
回答 6查看 8.6K关注 0票数 79

我有以下示例代码:

System.out.println(
       "Result: " +
        Stream.of(1, 2, 3)
                .filter(i -> {
                    System.out.println(i);
                    return true;
                })
                .findFirst()
                .get()
);
System.out.println("-----------");
System.out.println(
       "Result: " +
        Stream.of(1, 2, 3)
                .flatMap(i -> Stream.of(i - 1, i, i + 1))
                .flatMap(i -> Stream.of(i - 1, i, i + 1))
                .filter(i -> {
                    System.out.println(i);
                    return true;
                })
                .findFirst()
                .get()
);

输出如下:

1
Result: 1
-----------
-1
0
1
0
1
2
1
2
3
Result: -1

从这里我可以看到,在第一种情况下,stream确实表现得很懒惰--我们使用findFirst(),所以一旦我们有了第一个元素,我们的过滤lambda就不会被调用。然而,在使用flatMap的第二种情况下,我们看到尽管找到了满足过滤条件的第一个元素(它只是任何第一个元素,因为lambda总是返回true),流的更多内容仍然通过过滤函数提供。

我试图理解为什么它是这样的,而不是像第一个例子一样计算第一个元素后放弃。任何有用的信息都将不胜感激。

EN

回答 6

Stack Overflow用户

发布于 2015-03-24 17:55:26

输入流的元素一个接一个地懒惰地使用。第一个元素1由两个flatMap转换为流-1, 0, 1, 0, 1, 2, 1, 2, 3,因此整个流只对应于第一个输入元素。嵌套的流通过管道急切地具体化,然后变平,然后馈送到filter阶段。这解释了您的输出。

上述情况并不是源于一个基本的限制,但它可能会使事情变得更加复杂,从而使嵌套流变得更加懒惰。我怀疑这将是一个更大的挑战,使其性能。

作为比较,Clojure的lazy seqs为每一层嵌套获得另一层包装。由于这种设计,当嵌套执行到极致时,使用StackOverflowError的操作甚至可能失败。

票数 18
EN

Stack Overflow用户

发布于 2015-11-21 11:58:16

在我的免费StreamEx库中,我介绍了短路收集器。当使用短路收集器(如MoreCollectors.first())收集顺序流时,从源中只消耗一个元素。在内部,它是以一种非常糟糕的方式实现的:使用自定义异常来中断控制流。使用我的库,你的样本可以这样重写:

System.out.println(
        "Result: " +
                StreamEx.of(1, 2, 3)
                .flatMap(i -> Stream.of(i - 1, i, i + 1))
                .flatMap(i -> Stream.of(i - 1, i, i + 1))
                .filter(i -> {
                    System.out.println(i);
                    return true;
                })
                .collect(MoreCollectors.first())
                .get()
        );

结果如下:

-1
Result: -1
票数 6
EN

Stack Overflow用户

发布于 2021-05-19 15:08:48

虽然JDK-8075939已经在Java11中修复,并回传到10和8u222,但在使用Stream.iterator()JDK-8267359时,flatMap()仍然存在一个边缘情况,即在Java17中仍然存在。

Iterator<Integer> it =
    Stream.of("a", "b")
        .flatMap(s -> Stream
            .of(1, 2, 3, 4)
            .filter(i -> { System.out.println(i); return true; }))
        .iterator();

it.hasNext(); // This consumes the entire flatmapped stream
it.next();

打印

1
2
3
4

而这一点:

Iterator<Integer> it =
    Stream.of("a", "b")
        .flatMap(s -> Stream
            .iterate(1, i -> i)
            .filter(i -> { System.out.println(i); return true; }))
        .iterator();

it.hasNext();
it.next();

永不终止

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29229373

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档