Skip to Content

Java 16: Stream.toList() terminal operation

A nice quality of life improvement in Java 16

Posted on
Photo by Loren Isaac on Unsplash
Photo by Loren Isaac on Unsplash

There are plenty of larger features coming in Java 16 that get most of the focus, but I wanted to highlight one smaller change that might make your coding experience a bit better. This probably won’t end up being the reason you switch to Java 16, but changes like this are important because they add up and make the overall Java development experience better.

Introducing Stream.toList()

Performing some operations on a Stream and turning it into a List is a fairly common use case. How many times have you written something like this?

someList.stream()
    .map({ ... })
    .collect(Collectors.toList());  // <---- Verbose!

It turns out that this is a very common use case. It is not difficult code to write, but it is more verbose than it needs to be. Thankfully, Java 16 introduces a new method on Stream to make this use case easier to write:

someList.stream()
    .map({ ... })
    .toList();     // <---- NEW!

We can now call toList() as a terminal operation on a Stream<T> in Java!

Before using this or converting old code, we should note that there is an important difference between these examples. The new Stream.toList() returns an unmodifiable ArrayList, where Collectors.toList() returns a modifiable ArrayList. I think this is probably the right decision as we should favor immutability whenever possible. If we need a mutable list, we can always use the pre-Java 16 way. Just be careful when updating old code to this new syntax, this small difference may cause an UnsupportedOperationExcetpion to be thrown if the list ends up being modified elsewhere.

Like I said before, this probably won’t be the reason you switch to Java 16, but it’s a nice feature to have if you do.