Stream operations

Many of the methods of the Stream interface (those that have a functional interface type as a parameter) are called operations, because they are not implemented as traditional methods. Their functionalities are passed into the methods as a functions. The methods themselves are just shells that call a method of the functional interface, assigned as the type of the method parameter.

For example, let us look at the Stream<T> filter (Predicate<T> predicate) method. Its implementation is based on the call to the boolean test(T) method of the Predicate<T> function. So, instead of saying, "We use the filter() method of the Stream object to select some of the stream elements and skip others," the programmers prefer to say, "We apply the filter operation that allows some of the stream elements to get through, and skips others." It sounds similar to the statement, "We apply an operation of addition." It describes the nature of the action (operation), not the particular algorithm, which is unknown until the method receives the particular function.

So, there are three groups of methods in the Stream interface:

Stream processing is organized typically as a pipe using a fluent (dot-connected) style (see the Stream pipeline section). A Stream factory method or another stream source starts such a pipe, and a Terminal operation produces the pipe result or a side effect, and ends the pipe (thus, the name). An intermediate operation can be placed between the originating Stream object and the Terminal operation. It processes the stream elements (or not, in some cases), and returns the modified (or not modified) Stream object, so the next intermediate or Terminal operation can be applied.

Examples of intermediate operations are as follows:

There are some other methods that we will discuss in the Intermediate operations section.

The processing of the stream elements actually begins only when a Terminal operation starts executing. Then, all of the intermediate operations (if present) start processing. The stream closes (and cannot be reopened) as soon as the Terminal operation finishes execution. Examples of Terminal operations are forEach(), findFirst(), reduce(), collect(), sum(), max(), and other methods of the Stream interface that do not return Stream. We will discuss them in the Terminal operations section. 

All of the Stream methods support parallel processing, which is especially helpful in the case of a large amount of data processed on a multi-core computer. One must make sure that the processing pipeline does not use a context state that can vary across different processing environments. We will discuss this in the Parallel processing section.