86

How to create immutable objects in Java?

Which objects should be called immutable?

If I have class with all static members is it immutable?

4
  • possible duplicate of What is meant by immutable? Commented Jun 10, 2011 at 11:36
  • 1
    The question linked above is not the same, but the answers of that question should answer all of your questons. Commented Jun 10, 2011 at 11:36
  • If your class is all static members, it's stateless (no instance has individual state) and the question of mutable or immutable becomes moot. Commented Feb 14, 2014 at 16:43
  • is there any other way to initialize fields other than the constructor. I have more than 20 fields in my class. It is very difficult to initialize all the fields using the constructor, some fields are even optional also. Commented Feb 10, 2018 at 17:52

13 Answers 13

91

Below are the hard requirements of an immutable object.

  1. Make the class final
  2. make all members final, set them explicitly, in a static block, or in the constructor
  3. Make all members private
  4. No Methods that modify state
  5. Be extremely careful to limit access to mutable members(remember the field may be final but the object can still be mutable. ie private final Date imStillMutable). You should make defensive copies in these cases.

The reasoning behind making the class final is very subtle and often overlooked. If its not final people can freely extend your class, override public or protected behavior, add mutable properties, then supply their subclass as a substitute. By declaring the class final you can ensure this won't happen.

To see the problem in action consider the example below:

public class MyApp{

    /**
     * @param args
     */
    public static void main(String[] args){

        System.out.println("Hello World!");

        OhNoMutable mutable = new OhNoMutable(1, 2);
        ImSoImmutable immutable = mutable;

        /*
         * Ahhhh Prints out 3 just like I always wanted
         * and I can rely on this super immutable class 
         * never changing. So its thread safe and perfect
         */
        System.out.println(immutable.add());

        /* Some sneak programmer changes a mutable field on the subclass */
        mutable.field3=4;

        /*
         * Ahhh let me just print my immutable 
         * reference again because I can trust it 
         * so much.
         * 
         */
        System.out.println(immutable.add());

        /* Why is this buggy piece of crap printing 7 and not 3
           It couldn't have changed its IMMUTABLE!!!! 
         */
    }

}

/* This class adheres to all the principles of 
*  good immutable classes. All the members are private final
*  the add() method doesn't modify any state. This class is 
*  just a thing of beauty. Its only missing one thing
*  I didn't declare the class final. Let the chaos ensue
*/ 
public class ImSoImmutable{
    private final int field1;
    private final int field2;

    public ImSoImmutable(int field1, int field2){
        this.field1 = field1;
        this.field2 = field2;
    }

    public int add(){
        return field1+field2;
    }
}

/*
This class is the problem. The problem is the 
overridden method add(). Because it uses a mutable 
member it means that I can't  guarantee that all instances
of ImSoImmutable are actually immutable.
*/ 
public class OhNoMutable extends ImSoImmutable{   

    public int field3 = 0;

    public OhNoMutable(int field1, int field2){
        super(field1, field2);          
    }

    public int add(){
       return super.add()+field3;  
    }

}

In practice it is very common to encounter the above problem in Dependency Injection environments. You are not explicitly instantiating things and the super class reference you are given may actually be a subclass.

The take away is that to make hard guarantees about immutability you have to mark the class as final. This is covered in depth in Joshua Bloch's Effective Java and referenced explicitly in the specification for the Java memory model.

Sign up to request clarification or add additional context in comments.

10 Comments

what about all static members ?
the class does not need to be final for that.
@Nilesh: immutability is the property of instances. Static members don't usually relate to any single instance, so they don't come into the picture here.
Joshua Bloch's Item 15 on immutability - No methods that modify state, All fields final, All fields private, Ensure that class can't be extended, Ensure exclusive access to any mutable components.
@Jaochim - They absolutely are part of the equation - Take the example above if I add a mutable static member and use it in ImSoImmutable's add function you have the same problem. If a class is immutable then all aspects must be immutable.
|
14

Classes are not immutable, objects are.

Immutable means: my public visible state cannot change after initialization.

Fields do not have to be declared final, though it can help tremendously to ensure thread safety

If you class has only static members, then objects of this class are immutable, because you cannot change the state of that object ( you probably cannot create it either :) )

1 Comment

making all fields static limits all the intsances to share the same state which is not really useful.
13

Just don't add public mutator (setter) methods to the class.

8 Comments

what about all static members ? does reference or state of object change for such type of objects ?
Doesn't matter. If you cannot change them externally by some method, it's immutable.
that can not be answered as we don't know what the static memebers do ... ofc they could modify private fields. If they do that the class is not imutable.
And the class default constructor should be private or the class should be final. Just to avoid inheritance. Because inheritance violates encapsulation.
What about passing a mutable object e.g List to the immutable object then changing it from outside.. this is possible and it should be dealt with by using defensive copies during object creation
|
6

To make a class immutable in Java , you can keep note of the following points :

1. Do not provide setter methods to modify values of any of the instance variables of the class.

2. Declare the class as 'final' . This would prevent any other class from extending it and hence from overriding any method from it which could modify instance variable values.

3. Declare the instance variables as private and final.

4. You can also declare the constructor of the class as private and add a factory method to create an instance of the class when required.

These points should help!!

3 Comments

WRT #4 How does constructor visibilty affect mutabilty? String is immutable but has several public constructors.
As what @Ryan said, the same applies for instance variables: why should these be declared private?
Not sure why this answer has any upvotes. This answer is incomplete. It does not talk about mutable objects which is kind of important to be addressed. Please read @nsfyn55's explanation for a better understanding.
5

From oracle site, how to create immutable objects in Java.

  1. Don't provide "setter" methods — methods that modify fields or objects referred to by fields.
  2. Make all fields final and private.
  3. Don't allow subclasses to override methods. The simplest way to do this is to declare the class as final. A more sophisticated approach is to make the constructor private and construct instances in factory methods.
  4. If the instance fields include references to mutable objects, don't allow those objects to be changed:
    I. Don't provide methods that modify the mutable objects.
    II. Don't share references to the mutable objects. Never store references to external, mutable objects passed to the constructor; if necessary, create copies, and store references to the copies. Similarly, create copies of your internal mutable objects when necessary to avoid returning the originals in your methods.

Comments

4

An immutable object is an object that will not change its internal state after creation. They are very useful in multithreaded applications because they can be shared between threads without synchronization.

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

1. 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.

2. 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 references 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.

3. 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.

4. 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. 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.

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.

5. 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:

  1. Declare the immutable class as final so it can't be extended
  2. Declare all methods of the immutable class final so they can't be overriden
  3. Create a private constructor and a factory to create instances of the immutable class because a class with private constructors can't be extended

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

Below are few notable points:

  • Immutable objects do indeed make life simpler in many cases. They are especially applicable for value types, where objects don't have an identity so they can be easily replaced and they can make concurrent programming way safer and cleaner (most of the notoriously hard to find concurrency bugs are ultimately caused by mutable state shared between threads). However, for large and/or complex objects, creating a new copy of the object for every single change can be very costly and/or tedious. And for objects with a distinct identity, changing an existing objects is much more simple and intuitive than creating a new, modified copy of it.
  • There are some things you simply can't do with immutable objects, like have bidirectional relationships. Once you set an association value on one object, it's identity changes. So, you set the new value on the other object and it changes as well. The problem is the first object's reference is no longer valid, because a new instance has been created to represent the object with the reference. Continuing this would just result in infinite regressions.
  • To implement a binary search tree, you have to return a new tree every time: Your new tree will have had to make a copy of each node that has been modified (the un-modified branches are shared). For your insert function this isn't too bad, but for me, things got fairly inefficient quickly when I started to work on delete and re-balance.
  • Hibernate and JPA essentially dictate that your system uses mutable objects, because the whole premise of them is that they detect and save changes to your data objects.
  • Depending on the language a compiler can make a bunch of optimizations when dealing with immutable data because it knows the data will never change. All sorts of stuff is skipped over, which gives you tremendous performance benefits.
  • If you look at other known JVM languages (Scala, Clojure), mutable objects are seen rarely in the code and that's why people start using them in scenarios where single threading is not enough.

There's no right or wrong, it just depends what you prefer. It just depends on your preference, and on what you want to achieve (and being able to easily use both approaches without alienating die-hard fans of one side or another is a holy grail some languages are seeking after).

Comments

2
  • Don't provide "setter" methods — methods that modify fields or objects referred to by fields.
  • Make all fields final and private.
  • Don't allow subclasses to override methods. The simplest way to do this is to declare the class as final. A more sophisticated approach is to make the constructor private and construct instances in factory methods.
  • If the instance fields include references to mutable objects, don't allow those objects to be changed:
    • Don't provide methods that modify the mutable objects.
    • Don't share references to the mutable objects. Never store references to external, mutable objects passed to the constructor; if necessary, create copies, and store references to the copies. Similarly, create copies of your internal mutable objects when necessary to avoid returning the originals in your methods.

Comments

2

First of all, you know why you need to create immutable object, and what are the advantages of immutable object.

Advantages of an Immutable object

Concurrency and multithreading It automatically Thread-safe so synchronization issue....etc

Don't need to copy constructor Don't need to implementation of clone. Class cannot be override Make the field as a private and final Force callers to construct an object completely in a single step, instead of using a no-Argument constructor

Immutable objects are simply objects whose state means object's data can't change after the immutable object are constructed.

please see the below code.

public final class ImmutableReminder{
    private final Date remindingDate;

    public ImmutableReminder (Date remindingDate) {
        if(remindingDate.getTime() < System.currentTimeMillis()){
            throw new IllegalArgumentException("Can not set reminder" +
                    " for past time: " + remindingDate);
        }
        this.remindingDate = new Date(remindingDate.getTime());
    }

    public Date getRemindingDate() {
        return (Date) remindingDate.clone();
    }
}

Comments

1

an object is called immutable if its state can not be changed once created. One of the most simple way of creating immutable class in Java is by setting all of it’s fields are final.If you need to write immutable class which includes mutable classes like "java.util.Date". In order to preserve immutability in such cases, its advised to return copy of original object,

1 Comment

Its not that returning a copy is advised, its necessary. But its also necessary that a defensive copy is made in the constructor. Otherwise the object can be changed behind the scenes.
1

Immutable Objects are those objects whose state can not be changed once they are created, for example the String class is an immutable class. Immutable objects can not be modified so they are also thread safe in concurrent execution.

Features of immutable classes:

  • simple to construct
  • automatically thread safe
  • good candidate for Map keys and Set as their internal state would not change while processing
  • don't need implementation of clone as they always represent same state

Keys to write immutable class:

  • make sure class can not be overridden
  • make all member variable private & final
  • do not give their setter methods
  • object reference should not be leaked during construction phase

Comments

1

The following few steps must be considered, when you want any class as an immutable class.

  1. Class should be marked as final
  2. All fields must be private and final
  3. Replace setters with constructor(for assigning a value to a variable).

Lets have a glance what we have typed above:

//ImmutableClass
package younus.attari;

public final class ImmutableExample {

    private final String name;
    private final String address;

    public ImmutableExample(String name,String address){
        this.name=name;
        this.address=address;
    }


    public String getName() {
        return name;
    }

    public String getAddress() {
        return address;
    }

}

//MainClass from where an ImmutableClass will be called
package younus.attari;

public class MainClass {

    public static void main(String[] args) {
        ImmutableExample example=new ImmutableExample("Muhammed", "Hyderabad");
        System.out.println(example.getName());

    }
}

Comments

0

Commonly ignored but important properties on immutable objects

Adding over to the answer provided by @nsfyn55, the following aspects also need to be considered for object immutability, which are of prime importance

Consider the following classes:

public final class ImmutableClass {

  private final MutableClass mc;

  public ImmutableClass(MutableClass mc) {
    this.mc = mc;
  }

  public MutableClass getMutClass() {
    return this.mc;
  }
}

public class MutableClass {

  private String name;

  public String getName() {
    return this.name;
  }

  public void setName(String name) {
    this.name = name;
  }
}


public class MutabilityCheck {

public static void main(String[] args) {

  MutableClass mc = new MutableClass();

  mc.setName("Foo");

  ImmutableClass iMC = new ImmutableClass(mc);

  System.out.println(iMC.getMutClass().getName());

  mc.setName("Bar");

  System.out.println(iMC.getMutClass().getName());

  }

 }

Following will be the output from MutabilityCheck :

 Foo
 Bar

It is important to note that,

  1. Constructing mutable objects on an immutable object ( through the constructor ), either by 'copying' or 'cloing' to instance variables of the immutable described by the following changes:

    public final class ImmutableClass {
    
       private final MutableClass mc;
    
       public ImmutableClass(MutableClass mc) {
         this.mc = new MutableClass(mc);
       }
    
       public MutableClass getMutClass() {
         return this.mc;
       }
    
     }
    
     public class MutableClass {
    
      private String name;
    
      public MutableClass() {
    
      }
      //copy constructor
      public MutableClass(MutableClass mc) {
        this.name = mc.getName();
      }
    
      public String getName() {
        return this.name;
      }
    
      public void setName(String name) {
       this.name = name;
      } 
     }
    

still does not ensure complete immutability since the following is still valid from the class MutabilityCheck:

  iMC.getMutClass().setName("Blaa");
  1. However, running MutabilityCheck with the changes made in 1. will result in the output being:

    Foo
    Foo
    
  2. In order to achieve complete immutability on an object, all its dependent objects must also be immutable

Comments

0

From JDK 14+ which has JEP 359, we can use "records". It is the simplest and hustle free way of creating Immutable class.

A record class is a shallowly immutable, transparent carrier for a fixed set of fields known as the record components that provides a state description for the record. Each component gives rise to a final field that holds the provided value and an accessor method to retrieve the value. The field name and the accessor name match the name of the component.

Let consider the example of creating an immutable rectangle

record Rectangle(double length, double width) {}

No need to declare any constructor, no need to implement equals & hashCode methods. Just any Records need a name and a state description.

var rectangle = new Rectangle(7.1, 8.9);
System.out.print(rectangle.length()); // prints 7.1

If you want to validate the value during object creation, we have to explicitly declare the constructor.

public Rectangle {

    if (length <= 0.0) {
      throw new IllegalArgumentException();
    }
  }

The record's body may declare static methods, static fields, static initializers, constructors, instance methods, and nested types.

Instance Methods

record Rectangle(double length, double width) {

  public double area() {
    return this.length * this.width;
  }
}

static fields, methods

Since state should be part of the components we cannot add instance fields to records. But, we can add static fields and methods:

record Rectangle(double length, double width) {

  static double aStaticField;

  static void aStaticMethod() {
    System.out.println("Hello Static");
  }
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.