Creating an immutable version of a type using defensive copying


Creating an immutable

Some basic types and classes in Java are fundamentally mutable. For example, all array types are mutable, and so are classes like java.util.Data. This can be awkward in situations where an immutable type is mandated.

One way to deal with this is to create an immutable wrapper for the mutable type. Here is a simple wrapper for an array of integers

public class ImmutableIntArray {
	private final int[] array;
 
	public ImmutableIntArray(int[] array) {
		this.array = array.clone();
	}
	public int[] getValue() {
		return this.clone();
	}
}

This class works by using defensive copying to isolate the mutable state (the int[]) from any code that might mutate it:

  • The constructor uses clone() to create a distinct copy of the parameter array. If the caller of the constructor subsequent changed the parameter array, it would not affect the state of the ImmutableIntArray.
  • The getValue() method also uses clone() to create the array that is returned. If the caller were to change the result array, it would not affect the state of the ImmutableIntArray.

We could also add methods to ImmutableIntArray to perform read-only operations on the wrapped array; e.g. get its length, get the value at a particular index, and so on.

Note that an immutable wrapper type implemented this way is not type compatible with the original type. You cannot simply substitute the former for the latter.


The recipe for an immutable class

An immutable object is an object whose state cannot be changed. An immutable class is a class whose instances are immutable by design, and implementation. The Java class which is most commonly presented as an example of immutability is java.lang.String.

The following is a stereotypical example:

public final class Person {
	private final String name;
	private final String ssn; // (SSN == social security number)
 
	public Person(String name, String ssn) {
		this.name = name;
		this.ssn = ssn;
	}
 
	public String getName() {
		return name;
	}
 
	public String getSSN() {
		return ssn;
	}
}

A variation on this is to declare the constructor as private and provide a public static factory method instead.

The standard recipe for an immutable class is as follows:

  • All properties must be set in the constructor(s) or factory method(s).
  • There should be no setters.
  • If it is necessary to include setters for interface compatibility reasons, they should either do nothing or throw an exception.
  • All properties should be declared as private and final.
  • For all properties that are references to mutable types:
    • the property should be initialized with a deep copy of the value passed via the constructor, and
    • the property's getter should return a deep copy of the property value.
  • The class should be declared as final to prevent someone creating a mutable subclass of an immutable class.

A couple of other things to note:

  • Immutability does not prevent object from being nullable; e.g. null can be assigned to a String variable.
  • If an immutable classes properties are declared as final, instances are inherently thread-safe. This makes immutable classes a good building block for implementing multi-threaded applications.

Basic Programs