【问题标题】:Why doesn't Stream.limit work as expected in this snippet?为什么 Stream.limit 在此代码段中没有按预期工作?
【发布时间】:2015-12-09 07:25:53
【问题描述】:
List<Integer> integer = Stream.generate(new Supplier<Integer>() {
    int i = 0 ;

    @Override
    public Integer get() {
        return ++i;
    }
}).filter(j -> j < 5)
  .limit(10)   // Note the call to limit here
  .collect(Collectors.toList());

出乎我的意料,collect 调用永远不会返回。在filter 之前设置limit 会产生预期的结果。为什么?

【问题讨论】:

  • 顺便说一下,您可以使用Stream.iterate(1, i -&gt; i + 1).filter(...)... 而不是这个时髦的供应商。
  • @AlexisC。我不知道这个 API。谢谢!
  • 或者更好,IntStream.range()。

标签: java java-8 java-stream


【解决方案1】:

由于只有 4 个元素通过过滤器,limit(10) 永远不会达到 10 个元素,因此 Stream 管道不断生成新元素并将它们提供给过滤器,试图达到 10 个通过过滤器的元素,但由于只有前 4 个元素通过过滤器,处理永远不会结束(至少在 i 溢出之前)。

Stream 管道不够聪明,无法知道没有更多元素可以通过过滤器,因此它会不断处理新元素。

【讨论】:

  • Stream 管道不够聪明,无法知道没有更多元素可以通过过滤器”……事实上,it can't be
【解决方案2】:

翻转limitfilter 子句具有不同的行为。

如果你把limit放在前面,流将首先生成10个整数[1..10],然后过滤它们,只留下小于5的。

在原始排序中,首先应用filter,会生成整数并进行过滤,直到达到 10 个元素。这不是无限运算符,因为供应商中的i 最终会溢出,但需要一段时间才能到达MAX_INT,尤其是在慢速计算机上。

【讨论】:

  • 我没有考虑到最终的 int 溢出。 +1
  • 也许是关于优化器何时开始工作,但在我的机器上,溢出和随后的操作完成不到一秒……
【解决方案3】:

如果你想在达到第 5 个或收集到 10 个元素时停止 任一,Java-9 中添加了 Stream.takeWhile() 方法:

List<Integer> integer = Stream.generate(new Supplier<Integer>() {
    int i = 0 ;

    @Override
    public Integer get() {
        return ++i;
    }
}).takeWhile(j -> j < 5).limit(10).collect(Collectors.toList());

【讨论】:

    【解决方案4】:

    它将在供应商溢出并开始生成负数后完成。结果列表将包含:

    [1, 2, 3, 4, -2147483648, -2147483647, -2147483646, -2147483645, -2147483644, -2147483643]
    

    原因在其他答案中。在我的 i7 机器上,完成需要 40 秒。

    【讨论】:

      猜你喜欢
      • 2018-07-20
      • 1970-01-01
      • 2020-11-10
      • 2021-12-11
      • 1970-01-01
      • 1970-01-01
      • 2011-10-28
      • 2017-06-08
      • 2016-08-21
      相关资源
      最近更新 更多