有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

Java:流中的使用者接口无法按预期工作

我有两条语句,我希望它们“打印”相同的结果:

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”行中设置一个断点,但没有成功

那么,在使用“Consumer”处理每个元素时,我应该如何将第二条语句更改为使用“peek”来创建新的流呢

非常感谢


共 (4) 个答案

  1. # 1 楼答案

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

  2. # 2 楼答案

    peek()不是一个终端操作,它产生一个中间流。只有当流找到一个终端操作时,它才会被执行

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

    注意——第一个流有一个输出,因为forEach()是一个终端操作

  3. # 3 楼答案

    ^{},正如API的javadocs中所述,主要是为了调试目的,不建议在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.

  4. # 4 楼答案

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

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