Reputation: 55
I want to make the following class immutable, even though it has a mutable List member. 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;
}
}
Below is test class whose main()
function that modifies object state.
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]
Upvotes: 4
Views: 272
Reputation: 26740
If you're using 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;
}
}
Eclipse Collection's ImmutableList
and ListIterable
types are contractually immutable, meaning they don't have add()
and remove()
methods. This way, it's clear from the return type of getData()
that the returned list cannot be changed.
Both ImmutableList
and MutableList
extend ListIterable
so you could change the implementation from an 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.
Upvotes: 2
Reputation: 15729
In your constructor, go
this.data = Collections.unmodifiableList(new ArrayList(data));
For completeness and clarity, declare the data field as final
.
Upvotes: 6
Reputation: 347244
In you getData
method, instead of returning a reference to your List
like...
public List<Integer> getData() {
return data;
}
You could return an unmodifiable List
instead
public List<Integer> getData() {
return Collections.unmodifiableList(data);
}
See Collections.unmodifiableList
for more details...
Updated
As pointed out by user949300, you should also make a copy of the original list.
public MyImmutableClass(List<Integer> data) {
this.data = new ArrayList<Integer>(data);
}
This will prevent any one who has access to the original list from making modifications to it.
Upvotes: 7