35

can someone tell me What is the difference between intermediate and terminal operations for Stream?

Stream operations are combined into pipelines to process streams. All operations are either intermediate or terminal ..means?.

Naman
  • 27,789
  • 26
  • 218
  • 353
Amol Raje
  • 928
  • 3
  • 9
  • 16
  • 1
    streams are lazy , code actually do something when a terminal operation is invoked like sum , toarray etc and filter , map are intermediate , probably a dupe – Pavneet_Singh Dec 07 '17 at 05:50

5 Answers5

81

A Stream supports several operations and these operations are divided into intermediate and terminal operations.

The distinction between this operations is that an intermediate operation is lazy while a terminal operation is not. When you invoke an intermediate operation on a stream, the operation is not executed immediately. It is executed only when a terminal operation is invoked on that stream. In a way, an intermediate operation is memorized and is recalled as soon as a terminal operation is invoked. You can chain multiple intermediate operations and none of them will do anything until you invoke a terminal operation. At that time, all of the intermediate operations that you invoked earlier will be invoked along with the terminal operation.

All intermediate operations return Stream (can be chained), while terminal operations don't. Intermediate Operations are:

filter(Predicate<T>)
map(Function<T>)
flatMap(Function<T>)
sorted(Comparator<T>)
peek(Consumer<T>)
distinct()
limit(long n)
skip(long n)

Terminal operations produces a non-stream (cannot be chained) result such as primitive value, a collection or no value at all.

Terminal Operations are:

forEach
forEachOrdered
toArray
reduce
collect
min
max
count
anyMatch
allMatch
noneMatch
findFirst    
findAny

Last 5 are short-circuiting terminal operations.

MC Emperor
  • 22,334
  • 15
  • 80
  • 130
Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
14

As per javadoc:

  • Intermediate operation will transform a stream into another stream, such as map(MapperFn) or filter(Predicate)
  • Terminal operation will produce a result or side-effect, such as count() or forEach(Consumer)

Note that all intermediate operations will NOT be executed without a terminal operation at the end. So the pattern will be:

stream()
    .intemediateOperation1()
    .intemediateOperation2()
    ...
    .intemediateOperationN()
    .terminalOperation();
Hoa Nguyen
  • 13,452
  • 11
  • 45
  • 44
5

Terminal meaning ending the process, such as collecting a stream to a list, or aggregating a stream of values.

Intermediate as in transitioning to a new state, on the way to a terminal operation

OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
2

You probably noticed that when you define a stream, the methods aren't just called one by one on the whole stream, but rather they do something on each element from the stream. To be able to run these streams in parallel, for every element, there is basically a whole pipeline.

In order to create multiple pipelines, Java 8+ uses the builder pattern. With every intermediate step you add a filter or converter to the stack. In order to tell Java to generate pipelines from that stack of filters, you use a terminating step. That last step combines all the different pipelines. Usually it just returns the values in a defined format, e.g. a list, but it can also run a function once for each element, or reduce the results to a boolean or a number.

Hubert Grzeskowiak
  • 15,137
  • 5
  • 57
  • 74
2

To visualize let's take this code:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4);
        int sum = numbers.stream()
                .filter(n -> n % 2 == 0)
                .map(n -> n * n)
                .reduce(0, Integer::sum);

filter and map are intermediate operations, reduce is terminal.

  1. We create a stream from List (numbers.stream()), so we have: |1,2,3,4|
  2. filter values (numbers.stream().filter(n -> n % 2 == 0)): |1,2,3,4| ----- |filter|
  3. Map (numbers.stream().filter(n -> n % 2 == 0).map(n -> n * n)): |1,2,3,4| ----- |filter| ----- |map|
  4. finally we call reduce, which is terminal operation and the whole flow runs: |1,2,3,4| -> 4 3 2 1 -> |filter| -> 4 2 -> |map| -> 16 4 -> |reduce| -> 20

Notice that no data flows through the stream until the terminal operation is called.

Michu93
  • 5,058
  • 7
  • 47
  • 80