A [Stream](<https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html>)
will only be traversed when there is a terminal operation, like [count()](<https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#count-->)
, [collect()](<https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#collect-java.util.stream.Collector->)
or [forEach()](<https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#forEach-java.util.function.Consumer->)
. Otherwise, no operation on the [Stream](<https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html>)
will be performed.
In the following example, no terminal operation is added to the [Stream](<https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html>)
, so the [filter()](<https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#filter-java.util.function.Predicate->)
operation will not be invoked and no output will be produced because [peek()](<https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#peek-java.util.function.Consumer->)
is NOT a terminal operation.
IntStream.range(1, 10).filter(a -> a % 2 == 0).peek(System.out::println);
This is a Stream
sequence with a valid terminal operation, thus an output is produced.
You could also use forEach
instead of peek
:
IntStream.range(1, 10).filter(a -> a % 2 == 0).forEach(System.out::println);
Output:
2 4 6 8
After the terminal operation is performed, the Stream
is consumed and cannot be reused.
Although a given stream object cannot be reused, it’s easy to create a reusable Iterable
that delegates to a stream pipeline. This can be useful for returning a modified view of a live data set without having to collect results into a temporary structure.
List<String> list = Arrays.asList("FOO", "BAR");
Iterable<String> iterable = () -> list.stream().map(String::toLowerCase).iterator();
for (String str : iterable) {
System.out.println(str);
}
for (String str : iterable) {
System.out.println(str);
}
Output:
foo bar foo bar
This works because Iterable
declares a single abstract method Iterator<T> iterator()
. That makes it effectively a functional interface, implemented by a lambda that creates a new stream on each call.
In general, a Stream
operates as shown in the following image: