Creating an immutable list from an existing list using streams

  • A+

There is a list of Person objects.

List<Person> persons = generatePersons();

An unmodifiableList is created with it.

List<Person> unmodifiableList = Collections.unmodifiableList(persons);

I understand that unmodifiableList doesn't support add/remove/set operations. At the same time it is not immutable since it has a reference to an existing modifiable list persons and whenever changes are made to the persons list, the changes are reflected in unmodifiableList too.

An immutable list is created this way.

List<Person> immutableList = Collections.unmodifiableList(new ArrayList<>(persons));

This creates an immutable list since a conversion constructor is being used. No add/remove/set ops can be performed on immutableList nor any change in the original list persons would reflect in immutableList. Let's make an assumption that Person objects are immutable too.

Now, I want to create these two lists using streams.

The first one, I have created using:

List<Person> unmodifiablePersons = .collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));

I am lost at creating equivalent of immutableList through streams.

How can I do that?


I added a new Person object to the original list persons and printed the size of persons list and unmodifiablePersons. Both give me the same size. So, changes are being reflected to unmodifiablePersonsand hence it is not immutable yet. Am I missing something here?

Edit 2

Silly. Should have gone through the docs. unmodifiablePersons is indeed an immutable list. Also, the new Person object was added before the unmodifiablePersons was created and hence the above observation. Super silly.


Well in your first case someone has access to List<Person> unmodifiableList and can edit it, but when you collect no one has access to that List generated by Collectors.toList - so you are good.

What you are probably missing is that Collectors::toList will create a new List - which should really be obvious; and you wrap it into an unmodifiable one, thus the result of that is truly unmodifiable.

Also in java-10 there is special collector for that:

List<Integer> result = Arrays.asList(1, 2, 3, 4)         .stream()         .collect(Collectors.toUnmodifiableList()); 

This collector uses List::of internally - immutable collections added in java-9, thus for example they don't support nulls.


:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: