当前位置: 首页 > 面试题库 >

flatMap是否保证是懒惰的?

吕自明
2023-03-14
问题内容

考虑以下代码:

urls.stream()
    .flatMap(url -> fetchDataFromInternet(url).stream())
    .filter(...)
    .findFirst()
    .get();

fetchDataFromInternet当第一个URL够用时会被要求输入第二个URL吗?

我尝试了一个较小的示例,它看起来像预期的那样工作。即一个一个地处理数据,但是可以依靠这种行为吗?如果没有,.sequential().flatMap(...)帮助之前打电话吗?

    Stream.of("one", "two", "three")
            .flatMap(num -> {
                System.out.println("Processing " + num);
                // return FetchFromInternetForNum(num).data().stream();
                return Stream.of(num);
            })
            .peek(num -> System.out.println("Peek before filter: "+ num))
            .filter(num -> num.length() > 0)
            .peek(num -> System.out.println("Peek after filter: "+ num))
            .forEach(num -> {
                System.out.println("Done " + num);
            });

输出:

Processing one
Peek before filter: one
Peek after filter: one
Done one
Processing two
Peek before filter: two
Peek after filter: two
Done two
Processing three
Peek before filter: three
Peek after filter: three
Done three

更新 :如果对实施很重要,请使用官方Oracle JDK8

答案 :根据下面的评论和答案,flatmap部分是惰性的。即完全读取第一个流,并且仅在需要时才读取下一个。渴望读取一个流,但是读取多个流却很懒。

如果有这种行为,API应该让函数返回一个Iterable而不是一个流。


问题答案:

在当前的实现下flatmap渴望;像任何其他有状态中间操作(如sorteddistinct)一样。而且很容易证明:

 int result = Stream.of(1)
            .flatMap(x -> Stream.generate(() -> ThreadLocalRandom.current().nextInt()))
            .findFirst()
            .get();

    System.out.println(result);

从来没有像flatMap渴望的那样完成。例如:

urls.stream()
    .flatMap(url -> fetchDataFromInternet(url).stream())
    .filter(...)
    .findFirst()
    .get();

这意味着,对于每个urlflatMap即使您只关心单个操作,也将阻止其后的所有其他操作。因此,让我们假设,从url您的fetchDataFromInternet(url)生成10_000行中,即使您只关心一行,您findFirst也将不得不等待
所有 10_000的计算。

编辑

这在Java 10中已得到修复,在Java
10中我们恢复了懒惰:请参阅JDK-8075939

编辑2

这也已在Java
8(8u222)中修复:JDK-8225328



 类似资料:
  • 输出: 如果要执行此行为,API应该让函数返回而不是流。 换句话说:链接

  • 问题内容: 例如,如果我有以下语句: 如果foo1为true,python将检查foo2的条件吗? 问题答案: 是的,Python懒惰地评估布尔条件。 该文件说, 表达式x和y首先计算x;如果x为假,则返回其值;否则,将评估y并返回结果值。 表达式x或y首先计算x; 如果x为true,则返回其值;否则,将评估y并返回结果值。

  • 问题内容: 我在Linux上编写了一个C程序,该程序可以分配内存,并在一个循环中运行它,而TOP没有显示任何内存消耗。 然后我对该内存做了一些操作,而TOP确实显示了内存消耗。 当我分配内存时,我真的是“获取内存”,还是有一个“惰性”内存管理,仅当使用时才给我内存? (还有一个选项,当我使用它时,TOP只知道内存消耗,因此我不确定。) 谢谢 问题答案: 在Linux上,malloc使用sbrk()

  • 问题内容: 众所周知,JavaScript在所有现代浏览器实现中都是单线程的,但是它是在任何标准中指定的,还是仅根据传统?假设JavaScript始终是单线程的,是否完全安全? 问题答案: 这是个好问题。我很想说“是”。我不能 通常认为JavaScript具有脚本(*)可见的单个执行线程,因此,当您输入内联脚本,事件侦听器或超时时,您将完全处于控制状态,直到从块或函数的结尾返回为止。 (*:忽略浏

  • 问题内容: 我真的是在这里指身份平等。 例如,以下内容将始终打印 true 吗? 问题答案: 是的,类令牌是唯一的(对于任何给定的类加载器而言)。 即,您将始终 在相同的类加载器领域中 获得对相同物理对象的引用。但是,不同的类加载器将加载不同的类令牌,同时,当两个不同的类加载器加载相同的类定义时,会将相同的类定义视为不同。

  • 问题内容: PHP手册指出返回  “ 当前UNIX时间戳”  ᴀ  和返回 “当前Unix时间戳和微秒”  ʙ。 但是,是否 保证 这些功能的行为类似于严格符合POSIX.1的系统的行为? 具体来说,是否插入leap秒,使  |  的输出 在第二天的开始(也就是the秒的结尾) 向后* 跳1秒(在第二天的第一秒的整个过程中)