Monday, November 2, 2009

Immutable Collections

When we think of immutability in Java, the final keyword should come to mind. It's good practice to finalize whenever possible, particularly when working with multi-threaded applications. The less mutable state that exists, the less chance for side effects and bugs.
Working with collections is a bit trickier. When a class has a getter for a collection, things get a bit more difficult. Let's see what happens.

private final Collection<Object> aCollection;
public MyClass(Collection<Object> coll) {
aCollection = new LinkedList<Object>(coll);
}
public Collection<Object> getCollection() {
return aCollection;
}

Attempting to finalize a collection like this provides very little assurance that the collection will not be mutated. A client that calls getCollection can add or remove from the underlying collection as well as change the elements.
Addressing the first issue of adding or removing from the collection is easy to handle, yet I often see this overlooked. By using the Collections.unmodifiableXXX methods, we can easily create a collection that cannot be added or removed from. The constructor would now look like

public MyClass(Collection<Object> coll) {
aCollection = Collections.unmodifiableCollection(coll);
}

By finalizing in the constructor, this assures that neither private nor public methods can inadvertently mutate the structure of the list. The issue preventing a client from mutating the state of the objects in the list still exists. In order to prevent this, the objects would need to be completely immutable. There's not too much MyClass can do about this.
To sum up, try to make objects immutable whenever possible. You should be defaulting to final objects and unmodifiable collections and removing these restrictions only when absolutely necessary.

No comments:

Post a Comment