Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stream.peek() method in Java 8 vs Java 9

I am in the progress of learning through Java 8 lambda expressions and would like to ask about the following piece of Java code relating to the peek method in the function interface that I have come across.

On execution of the program on IDE, it gives no output. I was expecting it would give 2, 4, 6.

import java.util.Arrays; import java.util.List;  public class Test_Q3 {      public Test_Q3() {     }      public static void main(String[] args) {         List<Integer> values = Arrays.asList(1, 2, 3);         values.stream()               .map(n -> n * 2)               .peek(System.out::print)               .count();     } } 
like image 380
Patrick C. Avatar asked Jan 12 '18 07:01

Patrick C.


People also ask

What is the use of the PEEK () method in Java 8?

Java Stream peek() method returns a new Stream consisting of all the elements from the original Stream after applying a given Consumer action. Note that the peek() method is an intermediate Stream operation so, to process the Stream elements through peek() , we must use a terminal operation.

What is the difference between MAP and peek in Java 8?

In java-8 the list is populated, but in jdk-9 peek is not called at all. Since you are not using filter or flatmap you are not modifying the size of the Stream and count only needs it's size; thus peek is not called at all. Thus relying on peek is a very bad strategy.

Does Java 8 Stream improve performance?

In Java8 Streams, performance is achieved by parallelism, laziness, and using short-circuit operations, but there is a downside as well, and we need to be very cautious while choosing Streams, as it may degrade the performance of your application.

Is Java 8 Stream faster than for loop?

Yes, streams are sometimes slower than loops, but they can also be equally fast; it depends on the circumstances. The point to take home is that sequential streams are no faster than loops.


2 Answers

I assume you are running this under Java 9? You are not altering the SIZED property of the stream, so there is no need to execute either map or peek at all.

In other words all you care is about count as the final result, but in the meanwhile you do not alter the initial size of the List in any way (via filter for example or distinct) This is an optimization done in the Streams.

Btw, even if you add a dummy filter this will show what you expect:

values.stream ()       .map(n -> n*2)       .peek(System.out::print)       .filter(x -> true)       .count(); 
like image 144
Eugene Avatar answered Oct 14 '22 16:10

Eugene


Here's some relevant quotes from the Javadoc of Stream interface:

A stream implementation is permitted significant latitude in optimizing the computation of the result. For example, a stream implementation is free to elide operations (or entire stages) from a stream pipeline -- and therefore elide invocation of behavioral parameters -- if it can prove that it would not affect the result of the computation. This means that side-effects of behavioral parameters may not always be executed and should not be relied upon, unless otherwise specified (such as by the terminal operations forEach and forEachOrdered). (For a specific example of such an optimization, see the API note documented on the count() operation. For more detail, see the side-effects section of the stream package documentation.)

And more specifically from the Javadoc of count() method:

API Note:

An implementation may choose to not execute the stream pipeline (either sequentially or in parallel) if it is capable of computing the count directly from the stream source. In such cases no source elements will be traversed and no intermediate operations will be evaluated. Behavioral parameters with side-effects, which are strongly discouraged except for harmless cases such as debugging, may be affected. For example, consider the following stream:

List<String> l = Arrays.asList("A", "B", "C", "D"); long count = l.stream().peek(System.out::println).count(); 

The number of elements covered by the stream source, a List, is known and the intermediate operation, peek, does not inject into or remove elements from the stream (as may be the case for flatMap or filter operations). Thus the count is the size of the List and there is no need to execute the pipeline and, as a side-effect, print out the list elements.

These quotes only appear on the Javadoc of Java 9, so it must be a new optimization.

like image 38
Eran Avatar answered Oct 14 '22 16:10

Eran