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

牧云@^-^@ 提交于 2021-02-16 14:13:31

问题


I've got 2 statements, I expected that they should "print" same result:

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
    }
});

In fact, the first statement will print

a
b
c

Ok, but the second statement prints nothing. I tried to set a breakpoint in the line of "//breakpoint" inside IntelliJ, but it wasn't hit.

So how should I change the second statement to use "peek" as it create a new stream while processing every element using "Consumer"?

Thanks a lot.


回答1:


Stream.peek, as stated in the javadocs of the API as well, is meant mainly for debugging purposes and performing any update operations on the stream during the peek operation is not recommended.

For example, you can verify the intermediate stream state with the following code and what it eventually results in:

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

In general, this operation is an intermediate operation wouldn't be executed unless and terminal operation is performed on the stream as mentioned in the Stream operations and pipelines section of the docs and that is exactly the reason why your first statement will print.

Note: Though as suggested in a few other answers, the action within peek is not invoked in the cases when its able to optimize the result for some short-circuiting operations like findFirst etc.

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.




回答2:


peek() is not terminal operation, you need to add any terminal operation to make peek work, e.g.

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



回答3:


The peek() is not a terminal operation, it produces an intermediate stream. Your stream would be executed only when it finds a terminal operation.

For eg: if you add the count() terminal operation to your second stream, you will get the expected output.

Note - You got an output for the first stream because forEach() is a terminal operation.




回答4:


Stream operations are divided into intermediate (Stream-producing) operations and terminal (value- or side-effect-producing) operations. Intermediate operations are always lazy. So, Steam will start executing the operation pipeline once it gets any terminal operation. In your first case forEach is the terminal operation, so the stream executed. But in the second ca,se the last operation in the pipeline is peek() which is not a terminal operation.



来源:https://stackoverflow.com/questions/53455958/java-consumer-interface-in-a-stream-doesnt-work-as-expected

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!