Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating an immutable list from an existing list using streams

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 = persons.stream() .collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));

I am lost at creating equivalent of immutableList through streams.

How can I do that?

Edit:

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.

like image 792
Sara Avatar asked Oct 26 '18 17:10

Sara


2 Answers

With Java10+, you could have used an inbuilt capability copyOf for creating an unmodifiable list, like this:

List<Person> persons = generatePersons();       
List<Person> unmodifiableList = List.copyOf(persons);

Also, the current list that you're creating using Collector.collectingAndThen is actually immutable as mentioned in the documentation as well.

like image 110
Naman Avatar answered Sep 23 '22 11:09

Naman


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.

like image 45
Eugene Avatar answered Sep 23 '22 11:09

Eugene