How to create Immutable List in java?

JavaCollectionsImmutability

Java 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");

reference

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]

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser4768611View Question on Stackoverflow
Solution 1 - JavaaioobeView Answer on Stackoverflow
Solution 2 - JavaRoushanView Answer on Stackoverflow
Solution 3 - JavaMad PhysicistView Answer on Stackoverflow
Solution 4 - JavatonyhoanView Answer on Stackoverflow
Solution 5 - JavaDonald RaabView Answer on Stackoverflow
Solution 6 - JavaSaurabhView Answer on Stackoverflow
Solution 7 - JavaNoman AkhtarView Answer on Stackoverflow
Solution 8 - JavaAshish Agrawal YodleeView Answer on Stackoverflow