Code Pumpkin

How to create Immutable Class in Java

Immutable class is a class which once created, it's contents can not be changed. In other words, Immutable objects are the objects whose state can not be changed once constructed. 

In Java, String and all the wrapper classes e.g. Boolean, Integer, Long, etc are immutable classes. We can also create our own immutable class. 

Why should we write Immutable Classes?

Here are some of the advantages of Immutable Classes.

  1. Since the state of the immutable objects can not be changed once they are created, they are automatically synchronized/thread-safe and the overhead caused due to use of synchronization is avoided.
  2. The references to the immutable objects can be easily shared or cached without having to copy or clone them as their state can not be changed ever after construction.
  3. Immutable objects are good Map keys and Set elements, since they do not change once created.

Joshua Bloch's Effective Java has a very good explanation about why you should make your classes Immutable unless there is a strong reason to make them mutable.

Immutable Class from Effective Java

As per the guidelines provided in book, if a class cannot be made immutable, we should limit its mutability as much as possible.

Creating an Immutable class

Following are the requirements:

  1. Class must be declared as final. (So that child classes can not be created)
  2. Data members in the class must be declared as final and private (So that their values can not be changed after object creation)
  3. A parameterized constructor 
  4. No setters (To restrict any change in the value of the data members)
  5. Getter method for all the variables in it

For Example,

Let's create simple immutable User Object which is having only two fields : username and password


public final class User {
    private final String username;
    private final String password;

    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }

    public String getUsername() {
        return username;
    }

    public String getPassword() {
        return password;
    }
}

In most of the classes in our real applications, there are more than two fields. Also, most of these fields are not mandatory for object creation.

For example, a User in a real application will have a username, password, firstName, lastName,  emailAddress, etc., but for user creation here, only a username and password are required. So, we design our class as shown below:


public final class User {
    private final String username;
    private final String password;
    private String firstname;
    private String lastname;
    private String email;

    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }

    public String getUsername() {
        return username;
    }

    public String getPassword() {
        return password;
    }

    public String getFirstname() {
        return firstname;
    }
    public void setFirstname(String firstname) {
        this.firstname = firstname;
    }

    public String getLastname() {
        return lastname;
    }
    public void setLastname(String lastname) {
        this.lastname = lastname;
    }

    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
}

This class is not fully immutable because it has mutators, i.e. setters. So, instances of this class can be modified after creation. 

This approach has the disadvantage that objects can be in an inconsistent state  and you have to put in extra effort to ensure thread safety.

In such cases, you should use Builder Design Pattern to achieve immutability. The builder design pattern provides a way to build complex immutable objects. The process is:

  1. Provide one static inner class called UserBuilder in your Immutable class which has same fileds as your outer class.
  2. The client calls a constructor of the builder class with all the required fields and gets a builder object.
  3. The client calls setter like methods to set each optional parameter of interest.
  4. Finally the client calls the build method to generate the new object of outer class which is immutable.

Let's modify our User object using Builder Design Pattern:


public class ImmutableUser {
    private final String username;
    private final String password;
    private final String firstname;
    private final String lastname;
    private final String email;

    private ImmutableUser(UserBuilder builder) {
        this.username = builder.username;
        this.password = builder.password;
        this.firstname = builder.firstname;
        this.lastname = builder.lastname;
        this.email = builder.email;
    }

    public String getUsername() {
        return username;
    }
    public String getPassword() {
        return password;
    }
    public String getFirstname() {
        return firstname;
    }
    public String getLastname() {
        return lastname;
    }
    public String getEmail() {
        return email;
    }

    public static class UserBuilder {

        private final String username;
        private final String password;
        private String firstname;
        private String lastname;
        private String email;

        public UserBuilder(String username, String password) {
            this.username = username;
            this.password = password;
        }
        public UserBuilder firstName(String firsname) {
            this.firstname = firsname;
            return this;
        }
        public UserBuilder lastName(String lastname) {
            this.lastname = lastname;
            return this;
        }
        public UserBuilder email(String email) {
            this.email = email;
            return this;
        }
        public ImmutableUser build() {
            return new ImmutableUser(this);
        }
    }
}

Client Code:


public class CodePumpkinDemo {
	public static void main(String[] args) {
		ImmutableUser user = new ImmutableUser.UserBuilder("pumpkin", "password")
                                .firstName("Pumpkin")			
                                .lastName("PapaPumpkin")
                                .email("pumpkin@codepumpkin.com")
                                .build();
	}
}

Tags: , , , , ,


Comments and Queries

If you want someone to read your code, please put the code inside <pre><code> and </code></pre> tags. For example:
<pre><code class="java"> 
String foo = "bar";
</code></pre>
For more information on supported HTML tags in disqus comment, click here.
Total Posts : 93
Contribute Your Articles

Interview Experiences

Subscribe Us

Like Us On Facebook