With an immutable object, where is it proper to wrap a contained collection as unmodifiable? I see 3 options:
In the immutable object's factory:
public class ImmutableFactory { public Immutable build(){ List<Integer> values = new ArrayList<Integer>(); values.add(1); values.add(2); values.add(3); return new Immutable(Collections.unmodifiableList(values), "hello"); } }
In the immutable's contructor
public class Immutable { private final List<Integer> values; private final String hello; public Immutable(List<Integer> values, String hello) { this.values = Collections.unmodifiableList(values); this.hello = hello; } public List<Integer> getValues() { return values; } public String getHello() { return hello; } }
In the immutable's accessor (if applicable).
public class Immutable { private final List<Integer> values; private final String hello; public Immutable(List<Integer> values, String hello) { this.values = values; this.hello = hello; } public List<Integer> getValues() { return Collections.unmodifiableList(values); } public String getHello() { return hello; } }
Are there any other options and which one is proper?
First of all, your code in all places is indeed immutable but only because an
Integer
is immutable.If you had
private final List<SomeCustomClass> values;
instead,Collections.unmodifiableList(values);
would not guarantee that individualSomeCustomClass
of the list is immutable. You would have to code for that.Having said that, another option is to do a defencive deep copy of the list. This approach also offers immutability.
I'd say if you create Immutable collection then you need to protect yourself from somebody modifying list that was given as an argument to constructor, you should protectively copy it.
I personally have long ago switched to Guava collections as there you can find interfaces for immutable collections. Your constructor would look like that:
You'd be sure that argument you receive will not be modified by anyone.
It is usually a good idea to keep reference to immutable list within your immutable class as it then guarantees that you don't modify it by mistake.
Case (1) in my opinion makes sense only when factory method is the only way to create the immutable collection and even then it may break when someone refactors these classes. Unless there are other limitations it is always best to create self-sufficient classes.