Learn how to implement an immutable class in java with examples

This post covers an example of:

  • Immutable objects in Java
  • Creating immutables with Java 14
  • How to create an immutable class with mutable references

What is an immutable class in Java?

An immutable class is a class where, once the class instance is created, its content/state cannot be changed.

Each object has instance member variables and methods that change the state. However, immutable classes with instance members do not change their state via methods. Instead, the state is changed during object creation using the constructor.

Immutable classes are created based on specific design guidelines. The rules to be followed to make a class immutable include:

  • Declare the class as final to prevent it from being extended by other classes.
  • All methods of the class should be final.
  • Setters are not allowed.
  • Instance member variables should always be private and final.
  • Any method that doesn’t change the state of the object should be marked as final.
  • All instance variables are initialized using the constructor.

How to Create an Immutable Class in Java?

Here is the definition of an immutable class in Java:

public final class User{

    private final int id;
    private final String name;
    public User(int id, String name)
    {
        this.id = id;
        this.name=name;
    }
    public int getId(){
        return id;
    }
    public String getName(){
        return name;
    }
    public static void main(String args[]){
        System.out.println("Hello");
    }
}

Advantages of Immutable Classes

  • Allows classes to be thread-safe, preventing changes to their state during concurrent use.
  • Useful for caching purposes, as objects can be created with a default state and not changed thereafter.
  • Prevents extension or subclassing for inheritance.

How to Create an Immutable Class in Java 14

With Java 14, you can easily create an immutable class using the record keyword. Records have no instance variables, simplifying the class definition

public record User (id name, String name){
    this.id =id;
    this.name = name;
    public String getName() {
    return name;
  }
}

Features of record classes -

  • It is final and cannot be subclassed.
  • It can have instance methods and static classes.
  • No need to implement a constructor explicitly.
  • equals, hashCode, and toString methods are automatically generated.

How to Create an Immutable Class with a List of Immutable Objects

Suppose the User object contains multiple roles. Here, the User class is an immutable class, and the Role is a mutable class.

The following example demonstrates an immutable class referring to mutable object references:

import java.util.List;
import java.util.ArrayList;

final class User
{
    final int id;
    final String name;
    final List<Role> roles;
    Immutable(int id,String name,List<Role> roles)
    {
        this.id=id;
        this.name=name;
        this.roles=roles;
    }

    public List<Role> getRoles()
    {
        List<Role> roles=new ArrayList<>(this.roles);
        return roles;
    }

}
class Role implements Cloneable
{
    String name;
    Role(String name)
    {
        this.name=name;
    }
}

Conclusion

To summarize,

  • Immutable classes ensure stability and thread safety by prohibiting state changes after creation.
  • Java 14’s record simplifies the creation of immutable classes.
  • Immutable classes with mutable references should use defensive copying for maintaining immutability.