Collecting Stream Elements into Immutable Collection

In this tutorial, we’ll learn to collect the elements from a Java Stream into an immutable collection or unmodifiable collection.

1. Using Collectors.collectingAndThen() – Java 8

The Collectors.collectingAndThen() was introduced in Java 8 as part of lambda expression changes. This method takes two parameters a collector and a finishing function.

Arrays.asList(1, 2, 3, 4, 5)
	.stream()
	.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));

We can break the above function down into two steps:

  • Collectors.toList() will collect the Stream into a mutable List.
  • Collections.unmodifiableList() will convert the mutable List to an unmodifiable List of type java.util.Collections$UnmodifiableRandomAccessList.

We can write down both steps separately as follows:

List<Integer> mutableList = Arrays.asList(1, 2, 3, 4, 5)
	.stream()
	.collect(Collectors.toList());
	
List<Integer> unmodifiableList = Collections.unmodifiableList(mutableList);

See Also: Collecting Stream Items into List

2. Using Collectors.toUnmodifiableList() – Java 10

The Collectors.toUnmodifiableList() is a static function introduced in Java 10. This is a shortcut to the previous solution, which collects the Stream into an unmodifiable List in two steps.

It returns an object of type java.util.ImmutableCollections$ListN and will throw a NullPointerException if it encounters any null values. Note that ImmutableCollections is a container class for various immutable collections.

var unmodifiableList = Stream.of(1, 2, 3, 4, 5)
	.collect(Collectors.toUnmodifiableList());

We can use Collectors.toUnmodifiableSet() will collect the Stream elemens into an unmodifiable Set.

var unmodifiableSet = Stream.of(1, 2, 3, 4, 5)
	.collect(Collectors.toUnmodifiableSet());

Similarly, we can use Collectors.toUnmodifiableMap() to collect elements into an unmodifiable Map. It takes two parameters:

  • a key mapping function that would map the keys of the map
  • a value mapping function that would map the values of the corresponding keys.

In the following example, we will create a Map with the Integers in the List as keys and the square of the Integer as the value.

var unmodifiableMap = Stream.of(1, 2, 3, 4, 5).collect(Collectors.toUnmodifiableMap(i -> i, i -> i * i));

3. Using Stream.toList() – Java 16

With Java 16, Stream interface introduced a new default method toList() which gives back an immutable List.

var unmodifiableList = Stream.of(1, 2, 3, 4, 5)
	.toList();

4. Using Google’s Guava Library

Since Guava is an external library, it will have to be added to your classpath. If you’re using Maven, add the Guava dependency as follows:

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>31.1-jre</version>
</dependency>

4.1. Using ImmutableList.toImmutableList()

Starting with Guava v21.0, we can use ImmutableList.toImmutableList() static method which collects the elements into an Immutable List.

The ImmutableList.toImmutableList() method returns an object of type com.google.common.collect.RegularImmutableList and will throw a NullPointerException if it encounters any null values.

var unmodifiableList = Stream.of(1, 2, 3, 4, 5)
	.collect(ImmutableList.toImmutableList());

4.2. Using Collectors.collectingAndThen() with ImmutableList::copyOf

This approach is similar to the one described above. Here, instead, we use the ImmutableList::copyOf as the finishing function.

var unmodifiableList = Stream.of(1, 2, 3, 4, 5)
	.collect(Collectors.collectingAndThen(Collectors.toList(), ImmutableList::copyOf));

5. Immutable vs. Unmodifiable collections

Collections that do not support modification operations are referred to as unmodifiable. Unmodifiable collections are usually read-only views (wrappers) of other mutable collections. We can’t add, remove or clear them, but if we change the underlying collection, this collection’s view is also changed.

Collections that additionally guarantee that no change in the underlying collection object will be visible are referred to as immutable.

We can’t change immutable collections at all – they don’t wrap another collection – they have their own elements.

6. Conclusion

This Java Collections tutorial explored various ways to convert a Java Stream into an immutable collection. It is recommended to use the solution available in the latest Java version we are using.

Happy Learning !!

Leave a Reply

0 Comments
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions, and frequently asked interview questions.