4 questions on Java 8 Streams

Mehmet Akcay
3 min readFeb 24, 2021

java.util.stream (which was added in Java8) is composed of classes that enables processing stream of elements.

1.What is a stream?

A stream is a flow of objects that we can apply methods on to create the results we want. As it was stated here, it is not a data structure to store the elements. You create it, you make it go through a pipeline of computational operations, you get the results you want, it’s closed and that’s it.

One of the key properties of streams is it doesn’t change and manipulate the original source.

2. How to create a stream?

In order to create a stream, stream() or parallelStream() functions which are implemented in Collection interface (as default) can be used and they create a stream with the collection this method called on as the source.

List<Integer> list = new ArrayList<Integer>();Stream<Integer> stream = evens.stream();

2. What kind of operations can we have on streams?

There are two kinds of operations that can be applied on streams:

a. Intermediate operations: These operations turns streams to other streams and create an operation pipeline. They don’t get executed unless there is a terminal operation called on the stream, which is our next kind of operation.

Intermediate operation examples include filter, map, distinct, limit, skip, sorted and peek functions.

List<String> names = new ArrayList<String>(Arrays.asList("alex", "brian", "charles"));Stream<String> = names.stream()
.map(s->s.toUpperCase());

b. Terminal operations: These operations produce the result we want from the stream, and can’t be used to continue the chain. Streams can’t be reused after a terminal operation is called in the chain, stream is closed.

List<Integer> list = new ArrayList<Integer>(Arrays.asList(1,3,5,7,9));Stream<Integer> stream = list.stream();//Terminal operation is called
stream.forEach(s->{System.out.println(s);});
//Intermediate operation gives a java.lang.IllegalStateException stream.filter(s -> s > 5);

This exception occur for two reasons. First, a terminal operation is called on it and stream is closed. Secondly, even if an intermediate operation was called instead of foreach function, since the state of stream has changed, we cannot invoke a method on the changed stream outside of the operation pipeline.

Most stream operations accept lambda expressions and functional interfaces as parameter. These operations must be both non-interfering (meaning they don’t change the underlying source) and stateless ( which is deterministic ).

3. Why use streams?

One of the first questions that came to my mind while learning about streams was “Why would I use streams while I can do the same things using for loops and whatnot?”. The answer is in this sentence:

A key driver for this work is making parallelism more accessible to developers.

It was written by Brian Goetz in his article on Java 8 streams. Using parallel streams allow developers to execute these functions in parallel and enhances the performance. The key is performance.

* Operation pipeline: Chain of stream operations

** Functional interface: interfaces with exactly one abstract method. (They can have other default methods, though.) Details can be found here.

--

--

Mehmet Akcay

a geek who loves to understand the reasons behind things... and colors... Colors are cool.