How to create Immutable List in java?
JavaCollectionsImmutabilityJava Problem Overview
I need to convert mutable list object to immutable list. What is the possible way in java?
public void action() {
List<MutableClass> mutableList = Arrays.asList(new MutableClass("san", "UK", 21), new MutableClass("peter", "US", 34));
List<MutableClass> immutableList = immutateList(mutableList);
}
public List<MutableClass> immutateList(List<MutableClass> mutableList){
//some code here to make this beanList immutable
//ie. objects and size of beanList should not be change.
//ie. we cant add new object here.
//ie. we cant remove or change existing one.
}
###MutableClass
final class MutableClass {
final String name;
final String address;
final int age;
MutableClass(String name, String address, int age) {
this.name = name;
this.address = address;
this.age = age;
}
}
Java Solutions
Solution 1 - Java
Once your beanList
has been initialized, you can do
beanList = Collections.unmodifiableList(beanList);
to make it unmodifiable. (See https://stackoverflow.com/q/8892350/276052)
If you have both internal methods that should be able to modify the list, and public methods that should not allow modification, I'd suggest you do
// public facing method where clients should not be able to modify list
public List<Bean> getImmutableList(int size) {
return Collections.unmodifiableList(getMutableList(size));
}
// private internal method (to be used from main in your case)
private List<Bean> getMutableList(int size) {
List<Bean> beanList = new ArrayList<Bean>();
int i = 0;
while(i < size) {
Bean bean = new Bean("name" + i, "address" + i, i + 18);
beanList.add(bean);
i++;
}
return beanList;
}
(Your Bean
objects already seem immutable.)
As a side-note: If you happen to be using Java 8+, your getMutableList
can be expressed as follows:
return IntStream.range(0, size)
.mapToObj(i -> new Bean("name" + i, "address" + i, i + 18))
.collect(Collectors.toCollection(ArrayList::new));
Solution 2 - Java
In JDK 8:
List<String> stringList = Arrays.asList("a", "b", "c");
stringList = Collections.unmodifiableList(stringList);
In JDK 9:
List stringList = List.of("a", "b", "c");
Solution 3 - Java
Use Collections.unmodifiableList()
. You pass in your original ArrayList
and it returns a list that throws an exception if you try to add, remove or shift elements. For example, use return Collections.unmodifiableList(beanList);
instead of return beanList;
at the end of getImmutableList()
. main()
will throw an exception. The Collections
class has methods for all of the other common collection types besides List
as well.
Solution 4 - Java
From Java 10 on, List.copyOf(Collection)
can be used to return an unmodifiable list from the given collection. From source code of List.copyOf
method:
-
if the given collection is an unmodifiable List,
List.copyOf()
will not create a copy. -
if the given collection is mutable and modified, the returned list will not reflect such modifications. Meaning they are independent.
Solution 5 - Java
If are open to using a third party library, Eclipse Collections lets you convert from MutableList
to ImmutableList
and back again.
MutableList<String> mutable = Lists.mutable.with("a", "b", "c");
ImmutableList<String> immutable = mutable.toImmutable();
MutableList<String> mutableAgain = immutable.toList();
This also works with primitive collections.
MutableCharList mutable = CharLists.mutable.with('a', 'b', 'c');
ImmutableCharList immutable = mutable.toImmutable();
MutableCharList mutableAgain = immutable.toList();
If you have an ArrayList
as the mutable List
, the following will work.
List<String> mutable = new ArrayList<>(Arrays.asList("a", "b", "c"));
ImmutableList<String> immutable = Lists.immutable.withAll(mutable);
List<String> mutableAgain = immutable.toList();
Note: I am a committer for Eclipse Collections.
Solution 6 - Java
Make it immutable instead of using directly unmodifiableList on list as otherwise still original list can be changed.
Basically unModifiable Collection is a view, So indirectly it could still be 'modified' from some other reference that is modifiable. Also as its just a readonly view of annother collection , When the source collection changes unModifiable Collection will always present with latest values.
However immutable Collection can be treated as a readonly copy of another collection and can not be modified. In this case when the source collection changes , immutable Collection do not reflect the changes
List<String> immutableList=Collections.unmodifiableList(
new ArrayList<String>(modifiableList));
Using guava:
import java.util.*;
import com.google.common.collect.ImmutableList;
ImmutableList<String> iList = ImmutableList.copyOf(list);
Solution 7 - Java
Creating empty immutable list before java SE 9
Prior to Java 9, we have to use unmodifiableList() method of Collections class to create immutable list.
List<String> noElementList = new ArrayList<String>();
List<String> immuList = Collections.unmodifiableList(noElementList);
Creating Non-empty immutable list before Java SE 9
List<String> list = new ArrayList<String>();
list.add("Atto");
list.add("Rick");
list.add("Shalini");
List<String> immuList = Collections.unmodifiableList(list);
Java 9 – Creating Immutable list using static factory method of()
List<String> immuList = List.of();
Java 9 – Creating Non-empty immutable list
List<String> immuList = List.of("Atto", "Rick", "Shalini");
Solution 8 - Java
Below solution is for making list as Immutable without using any API.
Immutable Object with ArrayList member variable
public final class Demo {
private final List<String> list = new ArrayList<String>();
public Demo() {
list.add("A");
list.add("B");
}
public List<String> getImmutableList() {
List<String> finalList = new ArrayList<String>();
list.forEach(s -> finalList.add(s));
return finalList;
}
public static void main(String[] args) {
Demo obj = new Demo();
System.out.println(obj.getImmutableList());
obj.getImmutableList().add("C");
System.out.println(obj.getImmutableList());
}
}
So the actual list will not change, always output will be [A,B]