DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workkloads.

Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Writing DTOs With Java8, Lombok, and Java14+
  • Redefining Java Object Equality
  • Addressing Memory Issues and Optimizing Code for Efficiency: Glide Case
  • Singleton: 6 Ways To Write and Use in Java Programming

Trending

  • While Performing Dependency Selection, I Avoid the Loss Of Sleep From Node.js Libraries' Dangers
  • A Guide to Container Runtimes
  • Solid Testing Strategies for Salesforce Releases
  • Docker Model Runner: Streamlining AI Deployment for Developers
  1. DZone
  2. Coding
  3. Languages
  4. How to Create an Immutable Class in Java

How to Create an Immutable Class in Java

Here, we'll define the typical steps for creating an immutable class in Java and shed light on some common mistakes made while creating immutable classes.

By 
Hussein Terek user avatar
Hussein Terek
·
Dec. 12, 17 · Analysis
Likes (126)
Comment
Save
Tweet
Share
254.5K Views

Join the DZone community and get the full member experience.

Join For Free

An object is immutable if its state cannot change after construction. Immutable objects don’t expose any way for other objects to modify their state; the object’s fields are initialized only once inside the constructor and never change again.

In this article, we'll define the typical steps for creating an immutable class in Java and also shed light on the common mistakes which are made by developers while creating immutable classes.

1. Usage of Immutable Classes

Nowadays, the “must-have” specification for every software application is to be distributed and multi-threaded—multi-threaded applications always cause headaches for developers since developers are required to protect the state of their objects from concurrent modifications of several threads at the same time, for this purpose, developers normally use the Synchronized blocks whenever they modify the state of an object.

With immutable classes, states are never modified; every modification of a state results in a new instance, hence each thread would use a different instance and developers wouldn’t worry about concurrent modifications.

2. Some Popular Immutable Classes

String is the most popular immutable class in Java. Once initialized its value cannot be modified. Operations like trim(), substring(), replace() always return a new instance and don’t affect the current instance, that’s why we usually call trim() as the following:

String alex = "Alex";
alex = alex.trim();

Another example from JDK is the wrapper classes like: Integer, Float, Boolean … these classes don’t modify their state, however they create a new instance each time you try to modify them.

Integer a =3;
a += 3;

After calling a += 3, a new instance is created holding the value: 6 and the first instance is lost.

3. How Do We Create an Immutable Class

In order to create an immutable class, you should follow the below steps:

  1. Make your class final, so that no other classes can extend it.

  2. Make all your fields final, so that they’re initialized only once inside the constructor and never modified afterward.
  3. Don’t expose setter methods.
  4. When exposing methods which modify the state of the class, you must always return a new instance of the class.
  5. If the class holds a mutable object:
    • Inside the constructor, make sure to use a clone copy of the passed argument and never set your mutable field to the real instance passed through constructor, this is to prevent the clients who pass the object from modifying it afterwards.
    • Make sure to always return a clone copy of the field and never return the real object instance.

3.1. Simple Immutable Class

Let’s follow the above steps and create our own immutable class (ImmutableStudent.java).

package com.programmer.gate.beans;

public final class ImmutableStudent {

    private final int id;
    private final String name;

    public ImmutableStudent(int id, String name) {
        this.name = name;
        this.id = id;
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }
}

The above class is a very simple immutable class which doesn’t hold any mutable object and never expose its fields in any way; these type of classes are normally used for caching purposes.

3.2. Passing Mutable Objects to Immutable Class

Now, let’s complicate our example a bit, we create a mutable class called Age and add it as a field to ImmutableStudent:

package com.programmer.gate.beans;

public class Age {

    private int day;
    private int month;
    private int year;

    public int getDay() {
        return day;
    }

    public void setDay(int day) {
    this.day = day;
    }

    public int getMonth() {
    return month;
    }

    public void setMonth(int month) {
    this.month = month;
    }

    public int getYear() {
    return year;
    }

    public void setYear(int year) {
    this.year = year;
    }

}
package com.programmer.gate.beans;

public final class ImmutableStudent {

    private final int id;
    private final String name;
    private final Age age;

    public ImmutableStudent(int id, String name, Age age) {
    this.name = name;
    this.id = id;
    this.age = age;
    }

    public int getId() {
    return id;
    }

    public String getName() {
    return name;
    }

    public Age getAge() {
    return age;
    }
}

So, we added a new mutable field of type Age to our immutable class and assign it as normal inside the constructor.

Let’s create a simple test class and verify that ImmutableStudent is no more immutable:

public static void main(String[] args) {

    Age age = new Age();
    age.setDay(1);
    age.setMonth(1);
    age.setYear(1992);
    ImmutableStudent student = new ImmutableStudent(1, "Alex", age);

    System.out.println("Alex age year before modification = " + student.getAge().getYear());
    age.setYear(1993);
    System.out.println("Alex age year after modification = " + student.getAge().getYear());
}

After running the above test, we get the following output:

Alex age year before modification = 1992
Alex age year after modification = 1993

We claim that ImmutableStudent is an immutable class whose state is never modified after construction, however in the above example we are able to modify the age of Alex even after constructing Alex object. If we go back to the implementation of ImmutableStudent constructor, we find that age field is being assigned to the instance of the Age argument, so whenever the referenced Age is modified outside the class, the change is reflected directly on the state of Alex. Check out my Pass by value OR pass by reference article to more deeply understand this concept.

In order to fix this and make our class again immutable, we follow step #5 from the steps that we mention above for creating an immutable class. So we modify the constructor in order to clone the passed argument of Age and use a clone instance of it.

public ImmutableStudent(int id, String name, Age age) {
    this.name = name;
    this.id = id;
    Age cloneAge = new Age();
    cloneAge.setDay(age.getDay());
    cloneAge.setMonth(age.getMonth());
    cloneAge.setYear(age.getYear());
    this.age = cloneAge;
}

Now, if we run our test, we get the following output:

Alex age year before modification = 1992
Alex age year after modification = 1992

As you see now, the age of Alex is never affected after construction and our class is back to immutable.

3.3. Returning Mutable Objects From Immutable Class

However, our class still has a leak and is not fully immutable, let’s take the following test scenario:

public static void main(String[] args) {

    Age age = new Age();
    age.setDay(1);
    age.setMonth(1);
    age.setYear(1992);
    ImmutableStudent student = new ImmutableStudent(1, "Alex", age);

    System.out.println("Alex age year before modification = " + student.getAge().getYear());
    student.getAge().setYear(1993);
    System.out.println("Alex age year after modification = " + student.getAge().getYear());
}

Output:

Alex age year before modification = 1992
Alex age year after modification = 1993

Again according to step #4, when returning mutable fields from immutable object, you should return a clone instance of them and not the real instance of the field.

So we modify getAge() in order to return a clone of the object’s age:

public Age getAge() {
    Age cloneAge = new Age();
    cloneAge.setDay(this.age.getDay());
    cloneAge.setMonth(this.age.getMonth());
    cloneAge.setYear(this.age.getYear());

    return cloneAge;
}

Now the class becomes fully immutable and provides no way or method for other objects to modify its state.

Alex age year before modification = 1992
Alex age year after modification = 1992

4. Conclusion

Immutable classes provide a lot of advantages especially when used correctly in a multi-threaded environment. The only disadvantage is that they consume more memory than the traditional class since upon each modification of them a new object is created in the memory... but, a developer should not overestimate the memory consumption as its negligible compared to the advantages provided by these type of classes.

Finally, an object is immutable if it can present only one state to the other objects, no matter how and when they call its methods. If so it’s thread safe by any definition of thread-safe.

Object (computer science) Java (programming language)

Published at DZone with permission of Hussein Terek, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Writing DTOs With Java8, Lombok, and Java14+
  • Redefining Java Object Equality
  • Addressing Memory Issues and Optimizing Code for Efficiency: Glide Case
  • Singleton: 6 Ways To Write and Use in Java Programming

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!