Mutability in Java

Understanding Mutability

Reference URL: http://web.mit.edu/6.005/www/fa15/classes/09-immutability/

Immutable: An object that will always have the same value after it is created. Its value / contents cannot be changed.

Mutable objects on the other hand have methods that change the value of the object.

  • The String object is an example of an immutable object in Java. To add something to the end of a String, you have to create a new String object.

  • The StringBuilder is an example of a mutable type. It has methods to delete parts of the string, isert or replace characters.

The differences between mutability and immutability does not matter much when there is only one reference to an object. There are big differences in how they behave when there are other references to the same object. Let’s take the examples given below:

String s = "";
for (int i = 0; i < n; i++) {
  s = s + n;
}

Using immutable strings, many temporary copies of the string variable are created. This has an impact on performance.

StringBuilder sb = new StringBuilder();
for (int i = 0; i < n; i++) {
  sb.append(String.valueOf(n));
}
String s = sb.toString();

The mutable StringBuilder is designed to minimize this copying by using an internal data structure that avoids copying the string at every iteration, until the very end when the final String is required, with the toString() call. Hence, in this case, getting good performance is one reason why we use mutable objects. Another reason is the convenience of sharing. Two parts of a program can communicate more conveniently by sharing a common mutable data structure.

Risks behind mutation

  • Since mutable objects are more powerful than immutable objects, wouldn’t it be better to just use StringBuilder instead of String?

  • NO!!. The reason is that immutable* types are safer from bugs*, **easier to understand and more ready for change compared to immutable objects.

  • This is the reason why we use the String object!

Risks associated with mutable objects:

  • Passing mutable values to a function: The function can change the value of the mutable object. The calling code does not know if the object has been changed or not.

  • Returning mutable values from a function: After a mutable object has been returned, it is possible that the calling function may inadvertently change the value of this object.

Useful immutable types

Some commonly used immutable types in the Java API are as given below:

  • All primitive data types and primitive wrappers are immutable. For large numbers, BigInteger and BigDecimal are immutable.

  • Instead of Date, use the immutable java.time type for timekeeping.

  • Java’s collection types - List, Set, Map, etc. are all mutable. You can use their unmodifiable views such as Collections.unmodifiableList, Collections.unmodifiableSet and Collections.unmodifiableMap. These provide a wrapper around the underlying list / set / map, which can be passed on to clients that require a reference.

Note: Java gives us the ability to make variables immutable with the final keyword. This also serves as a means of documentation and increases code readability.