How can I make this class immutable despite having a mutable member?

I want to make the next class immutable, even if it has a mutable list. How can I achieve this?

class MyImmutableClass { private List<Integer> data; public MyImmutableClass(List<Integer> data) { this.data = data; } public List<Integer> getData() { return data; } } 

The following is a test class, the main() function, which changes the state of an object.

 class TestMyImmutableClass{ public static void main(String[] args) { List<Integer> data = new ArrayList<Integer>(); data.add(2); data.add(5); MyImmutableClass obj = new MyImmutableClass(data); obj.getData().add(3); System.out.println("Data is; " + obj.getData()); } } 

O / P: Data is; [2, 5, 3] Data is; [2, 5, 3]

+4
source share
3 answers

If you use Eclipse Collections , you can change the type of MyImmutableClass.data to ImmutableList .

 class MyImmutableClass { private ImmutableList<Integer> data; public MyImmutableClass(List<Integer> data) { this.data = Lists.immutable.withAll(data); } public ListIterable<Integer> getData() { return data; } } 

The types Eclipse Collection ImmutableList and ListIterable are immutable by contract, that is, they do not have the add() and remove() methods. Thus, the return type of getData() shows that the returned list cannot be changed.

Both ImmutableList and MutableList extend ListIterable , so you can change the implementation from ImmutableList to an unmodifiable list without changing the API.

 class MyImmutableClass { private MutableList<Integer> data; public MyImmutableClass(List<Integer> data) { this.data = Lists.mutable.withAll(data); } public ListIterable<Integer> getData() { return data.asUnmodifiable(); } } 

Note. I am a committer for Eclipse collections.

+2
source

In your getData method getData instead of returning a link to your List as ...

 public List<Integer> getData() { return data; } 

Instead, you can return an unmodifiable List

 public List<Integer> getData() { return Collections.unmodifiableList(data); } 

See Collections.unmodifiableList details.

Update

As indicated by user 949300, you should also make a copy of the original list.

 public MyImmutableClass(List<Integer> data) { this.data = new ArrayList<Integer>(data); } 

This will prevent anyone who has access to the source list from making changes to it.

+7
source

In your constructor, go

this.data = Collections.unmodifiableList(new ArrayList(data));

For completeness and clarity, declare the data field as final .

+6
source

Source: https://habr.com/ru/post/1500642/


All Articles