How Java 8 Streams work?
Streams support functional-style operations on streams of elements, such as map-reduce transformations on collections.
Stream operations are divided into intermediate and terminal operations, and are combined to form stream pipelines. A stream pipeline
consists of a source (such as a Collection, an array, a generator function, or an I/O channel); followed by zero or more intermediate
operations such as Stream.filter or Stream.map; and a terminal operation such as Stream.forEach or Stream.reduce.
Intermediate operations return a new stream. They are always lazy; executing an intermediate operation such as
filter() does not actually perform any filtering, but instead creates a new stream that, when traversed, contains the elements
of the initial stream that match the given predicate. Traversal of the pipeline source does not begin until the terminal
operation of the pipeline is executed.
Terminal operations, such as Stream.forEach or IntStream.sum, may traverse the stream to produce a result or
a side-effect. After the terminal operation is performed, the stream pipeline is considered consumed, and can no longer
be used; if you need to traverse the same data source again, you must return to the data source to get a new stream. In
almost all cases, terminal operations are eager, completing their traversal of the data source and processing of the
pipeline before returning. Only the terminal operations iterator() and spliterator() are not; these are provided as an
"escape hatch" to enable arbitrary client-controlled pipeline traversals in the event that the existing operations are not
sufficient to the task.
Intermediate operations are further divided into stateless and stateful operations. Stateless operations, such
as filter and map, retain no state from previously seen element when processing a new element -- each element can be processed
independently of operations on other elements. Stateful operations, such as distinct and sorted, may incorporate state from
previously seen elements when processing new elements.
Stateful operations may need to process the entire input before producing a result. For example, one cannot
produce any results from sorting a stream until one has seen all elements of the stream. As a result, under parallel
computation, some pipelines containing stateful intermediate operations may require multiple passes on the data or may
need to buffer significant data. Pipelines containing exclusively stateless intermediate operations can be processed in a
single pass, whether sequential or parallel, with minimal data buffering.
Here is a simple example on Steam operations and pipelines: The below example, combines filtering a list based on
number of characters, converting them to upper case, sorting and finally printing them into single line of code, which is the power of
streams.
package com.java2novice.streams;
import java.util.Arrays;
import java.util.List;
public class StreamExample {
public static void main(String a[]) {
List<String> vechicles = Arrays.asList("bus", "car", "bicycle", "flight", "train");
vechicles.stream().filter(str->str.length() > 3).map(String::toUpperCase).sorted().forEach(System.out::println);;
}
}
|
|