Immutable Objects in Java

An immutable object is an object that will not change its internal state after creation.

Immutable objects are very useful in multithreaded applications because they can be shared between threads without synchronization

Immutable objects are always thread safe.

Threads Are Everywhere

It is not important if you write explicit multithreaded application or not, often you work in a multithreaded environment without directly managing thread instances.

Here are few example of multithreaded applications where the programmer doesn't manually invoke the creation of new threads:

Creating an Immutable Object

To create an immutable object you need to follow some simple rules:

Now we discover point by point the reasons of the five rules explained before.

Don't add any setter method

If you are building an immutable object its internal state will never change. Task of a setter method is to change the internal value of a field, so you can't add it.

Declare all fields final and private

A private field is not visible from outside the class so no manual changes can't be applied to it. 

Declaring a field final will guarantee that if it references a primitive value the value will never change, if it reference an object the reference can't be changed. This is not enough to ensure that an object with only private final fields is not mutable. Here is an example showing an object with a private final field and an example on how to mutate its internal state:

public class DateContainer {
  private final Date date;

  public DateContainer() {
      this.date = new Date();
  }

  public Date getDate() {
    return date;
  }
}

....


  DateContainer dateContainer = new DateContainer();
  System.out.println(dateContainer.getDate());
  dateContainer.getDate().setTime(dateContainer.getDate().getTime() + 1000);
  System.out.println(dateContainer.getDate());
  // Now dateContainer date is 1 second after

If a field is a mutable object create defensive copies of it for getter methods

We have seen before that defining a field final and private is not enough because it is possible to change its internal state. To solve this problem we need to create a defensive copy of that field and return that field every time it is requested.

Here is the previous class with that modification:

public class DateContainer {
  private final Date date;

  public DateContainer() {
      this.date = new Date();
  }

  public Date getDate() {
    return new Date(date.getTime());
  }
}

....


  DateContainer dateContainer = new DateContainer();
  System.out.println(dateContainer.getDate());
  dateContainer.getDate().setTime(dateContainer.getDate().getTime() + 1000);
  System.out.println(dateContainer.getDate());
  // Now dateContainer date is not changed because we changed the copy, 
  // not the original date

If a mutable object passed to the constructor must be assigned to a field create a defensive copy of it

The same problem happens if you hold a reference passed to the constructor because it is possible to change it.

Here we show a modified example of DateContainer that accept a Date for the constructor and we will see how it is possible to change its internal state:

public class DateContainer {
  private final Date date;

  public DateContainer(Date date) {
      this.date = date;
  }

  public Date getDate() {
    return new Date(date.getTime());
  }
}

....

  Date date = new Date();
  DateContainer dateContainer = new DateContainer(date);
  System.out.println(dateContainer.getDate());
  date.setTime(date.getTime() + 1000);
  System.out.println(dateContainer.getDate());
  // Now dateContainer date is 1 second after also if the getter method
  // create a defensive copy of date. We changed the reference passed to the
  // constructor, not the copy.

So holding a reference to an object passed to the constructor can create mutable objects. To solve this problem it is necessary to create a defensive copy of the parameter if they are mutable objects:

public class DateContainer {
  private final Date date;

  public DateContainer(Date date) {
      this.date = new Date(date.getTime());
  }

  public Date getDate() {
    return new Date(date.getTime());
  }
}

....

  Date date = new Date();
  DateContainer dateContainer = new DateContainer(date);
  System.out.println(dateContainer.getDate());
  date.setTime(date.getTime() + 1000);
  System.out.println(dateContainer.getDate());
  // Now dateContainer date is not changed. We create a copy on the constructor
  // so a change to the external date will not affect the internal state of
  // DateContainer instance

Note that if a field is a reference to an immutable object is not necessary to create defensive copies of it in the constructor and in the getter methods it is enough to define the field as final and private. As an example of common immutable objects there are String, all primitive wrappers (Integer, Long, Double, Byte....), BigDecimal, BigInteger.

Don't allow subclasses to override methods

If a subclass override a method it can return the original value of a mutable field instead of a defensive copy of it.

To solve this problem it is possible to do one of the following:

If you follow those simple rules you can freely share your immutable objects between threads because they are thread safe!

 

 

 

 

Top