Java 8 Stream – An Introduction

Stream is basically a sequence of elements. The basic definition of stream is – A sequence of elements supporting sequential and parallel aggregate operations. Java 8 provided an additional package java.util.stream. It contains classes to support functional operations on streams of elements.

  • Stream is not a data structure like a collection and does not store elements. It is a sequence of elements. A stream provides an interface to a sequenced set of values of a particular type.
  • The source of stream might be an array, an I/O channel, a collection, a generator function.
  • Streams do not provide a means to directly access or manipulate their elements. Stream declaratively describes what its source is and what operations will be performed on source.
  • Stream supports various operations like filter, map, reduce, find etc. Stream supports operations similar to SQL. Various stream operations are composed into stream pipeline.
  • A stream pipeline contains the following components:
    1. A source – a collection, an array, a generator function, or an I/O channel.
    2. Zero or more intermediate operations. An intermediate operation transforms a stream into another stream. For example, filter.
    3. A terminal operation – A terminal operation produces a result. For example, count().
  • A stream should be operated only once. A stream implementation may throw IllegalStateException if the stream is being reused.
  • Stream pipelines may execute either sequentially or parallelly. One can define this while creating stream. For example, Collection.stream() creates a sequential stream, and Collection.parallelStream() creates a parallel stream.
  • Streams implement AutoCloseable. Generally, only streams having source as IO channel actually need to be closed after use. Streams having source as collections, array or generating functions do not actually need to be closed after use as these sources of stream do no require special resource management.
  • Streams are lazy in nature. Computation of the source is performed when terminal operation is initiated, and source elements are consumed only as needed.
  • There are primitive specialization of streams available like IntStream, LongStream, and DoubleStream.
  • In comparison to collections which use external iteration, streams use internal iteration. In external iteration, your program defines and handles how a collection is iterated. Stream does the iteration behind the scene.

We’ll discuss various operations on stream later. Let us see one example without stream and with stream.

Program to calculate sum of elements of a list without using stream:

private static int getSumWithIterator(List<Integer> list) {
		Iterator<Integer> it = list.iterator();
		int sum = 0;
		while (it.hasNext()) {
			int num = it.next();
			if (num > 5) {
				sum += num;
		return sum;

This program calculates sum of elements in a list which are greater than 5.

Let us write this code using stream.

private static int getSumWithStream(List<Integer> list) {
		return list.stream().filter(i -> i > 5).mapToInt(i -> i).sum();

Lets understand this program with the help of following points:

  • A stream is created using stream() on a list. The source of this stream is a list.
  • filter is used to filter elements greater than 5. filter is an intermediate operation and creates another stream.
  • mapToInt is an intermediate operation which results IntStream.
  • sum() is a terminal operation and returns sum of elements.

In this tutorial, we briefly discussed stream in Java. In the next tutorials, we’ll discuss various operations on stream.