【问题标题】:Is the skip() method a short circuiting-operation?skip() 方法是短路操作吗?
【发布时间】:2019-01-05 09:39:19
【问题描述】:

我在阅读 Java 流的短路操作,在一些文章中发现 skip() 是一种短路操作。

在另一篇文章中,他们没有提到 skip() 是一种短路操作。

现在我很困惑; skip() 是不是短路操作?

【问题讨论】:

    标签: java java-8 java-stream short-circuiting


    【解决方案1】:

    From the java doc under the "Stream operations and pipelines" section

    一个 中间操作是短路的,如果,当出现 无限输入,因此可能会产生有限流。一个终端 如果出现无限输入,则操作是短路的, 它可能会在有限的时间内终止。

    强调我的。

    如果您要在无限输入上调用skip,它不会产生有限流,因此不会产生短路操作。

    JDK8 中唯一的短路中间操作是 limit,因为它允许对无限流的计算在有限时间内完成。

    示例:

    如果您要使用skip 执行此程序:

    String[] skip = Stream.generate(() -> "test") // returns an infinite stream
                          .skip(20) 
                          .toArray(String[]::new);
    

    它不会产生 finite 流,因此您最终会得到类似于“java.lang.OutOfMemoryError: Java heap space”的内容。

    而如果您使用limit 执行此程序,它将导致计算在finite 时间内完成:

    String[] limit = Stream.generate(() -> "test") // returns an infinite stream
                           .limit(20)
                           .toArray(String[]::new);
    

    【讨论】:

    • 除了limit,这里还有一个:stackoverflow.com/a/51575391/1059372
    • @Eugene limitjdk8 中唯一的一个,这就是问题的标记。我想我会通过在答案中说明这一点来更清楚地说明这一点。
    【解决方案2】:

    只想在这里加上我的两分钱,一般这种短路流的想法是无限复杂的(至少对我来说,至少在我必须从头开始的意义上通常头两次)。顺便说一句,我会在答案的末尾找到skip

    我们以这个为例:

    Stream.generate(() -> Integer.MAX_VALUE);
    

    这是一个无限的流,我们都可以同意这一点。让我们通过一个记录为这样的操作来短路它(不像skip):

    Stream.generate(() -> Integer.MAX_VALUE).anyMatch(x -> true);
    

    这很好用,添加filter怎么样:

    Stream.generate(() -> Integer.MAX_VALUE)
          .filter(x -> x < 100) // well sort of useless...
          .anyMatch(x -> true);
    

    这里会发生什么?好吧,这永远不会结束,即使有像 anyMatch 这样的短路操作 - 但它从来没有真正短路任何东西。

    另一方面,filter 不是短路操作,但您可以这样做(仅作为示例):

    someList.stream()
            .filter(x -> {
               if(x > 3) throw AssertionError("Just because");            
    })
    

    是的,它很丑陋,但它很短路......这就是我们(强调我们,因为 很多 人不同意)实现short-circuiting reduce 的方式 - 抛出一个没有堆栈的异常痕迹。

    java-9 中添加了另一个短路操作:takeWhile,其行为类似于limit,但在特定条件下。

    公平地说,关于skip 的大部分答案都是 Aomine 给出的,但最简单的答案是 没有这样记录。通常(在某些情况下文档会被更正),但这是您应该查看的第一个指示。例如,请参阅limittakeWhile,其中明确表示:

    这是一个短路状态的中间操作

    【讨论】:

    • 当你说“最简单的答案是它没有被记录为这样”。不仅如此,我相信 “如果在呈现无限输入时,它可能会产生有限流,则中间操作是短路的,因此” 的引用绰绰有余为了我。 +1
    • @Aomine 你是对的,问题是这是包文档,考虑到通常在 IDE 中处理得多么糟糕,它很少被阅读。您通常只阅读方法文档本身
    • 我想我认为自己是那些总是先阅读包文档然后再阅读方法文档的人之一。也就是说,在方法文档中更加明确也会让我猜对某些人来说事情变得更好一些。记得不久前我们在iterator() on parallel stream guarantee encounter order? 上回答的这篇文章,您必须深入研究才能找到答案,直到 Stuart Marks 说这是规范中的疏忽
    • 我并不是要在聊天中发送垃圾邮件:),但我说的“你必须看起来很深”应该真的是“一个人必须看起来很深”,因为我不是指给你,而不是一般人。
    • @Aomine 好吧,有很多未指定的东西,尤其是使用 Stream API 时,许多人仍然没有阅读包文档甚至类文档。但是为了公平对待这些开发人员,我有一种强烈的感觉,javadoc 维护人员并不认为任何人仍在阅读这些糟糕的 frameset-html 页面,尤其是在引入模块之后,这是一个无法导航的混乱,甚至内部链接也经常被破坏似乎没人在乎……
    猜你喜欢
    • 2011-07-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-05
    • 2015-12-06
    • 2014-06-08
    • 2013-03-11
    • 2015-04-08
    相关资源
    最近更新 更多