Java:流中的消费者界面未按预期工作

Java: Consumer interface in a stream doesn't work as expected

我有 2 个陈述,我希望它们 "print" 相同的结果:

Arrays.stream("abc".split("")).forEach(System.out::println);//first
Arrays.stream("abc".split("")).peek(new Consumer<String>() {//second
    @Override
    public void accept(String s) {
        System.out.println(s);//breakpoint
    }
});

其实第一条语句会打印

a
b
c

好的,但是第二个语句没有打印任何内容。我尝试在 IntelliJ 中的“//breakpoint”行设置断点,但没有被击中。

那么我应该如何更改第二个语句以使用 "peek" 因为它在使用 "Consumer" 处理每个元素时创建一个新流?

非常感谢。

peek()不是终端操作,它产生中间流。您的流只有在 发现 终端操作时才会执行。

例如:如果您将 count() 终端操作添加到您的第二个流,您将获得预期的输出。

注意 - 您得到了第一个流的输出,因为 forEach() 是一个终端操作。

peek() 不是终端操作,您需要添加任何终端操作才能使 peek 工作,例如

Arrays.stream("abc".split("")).peek(new Consumer<String>() { //second
    @Override
    public void accept(String s) {
        System.out.println(s);//breakpoint
    }
}).count();

流操作分为中间(Stream-producing)操作和终端(value- or side-effect-producing)操作。中间操作总是 lazy。因此,一旦获得任何终端操作,Steam 就会开始执行操作管道。在您的第一种情况下 forEach 是终端操作,因此执行了流。但在第二种情况下,管道中的最后一个操作是 peek(),这不是终端操作。

Stream.peek,正如 API 的 javadoc 中所述,主要用于调试目的,不建议在 peek 操作期间对流执行任何更新操作。

例如,您可以使用以下代码验证中间流状态及其最终结果:

Arrays.stream("acb".split(""))
      .peek(System.out::println) // print a  c  b 
      .sorted()
      .forEach(System.out::println); // print a  b  c

一般来说,这个操作是一个中间操作不会被执行,除非终端操作如前所述在流上执行在文档的 Stream operations and pipelines 部分,这正是您的 第一条语句将打印 .

的原因

注意:尽管如其他一些答案中所建议的那样,peek 中的操作 在能够优化某些短路操作(如 findFirst

的结果的情况下不会被调用

In cases where the stream implementation is able to optimize away the production of some or all the elements (such as with short-circuiting operations like findFirst, or in the example described in count()), the action will not be invoked for those elements.