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
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

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

  • One Query, Four GPUs: Tracing a Distributed Training Stall Across Nodes
  • From AI Chaos to Control: Building Enterprise-Grade LLM Gateways With MuleSoft Anypoint
  • From Indicators to Insights: Automating IOC Enrichment Using Python and Threat Feeds
  • Designing API-First EMR Architectures in .NET: Enabling Modular Growth in Compliance-Driven Systems
  1. DZone
  2. Coding
  3. Languages
  4. Immutable Objects in Java

Immutable Objects in Java

An overview plus some practical tips on immutable objects in Java.

By 
Davide Lorenzo Marino user avatar
Davide Lorenzo Marino
·
Dec. 18, 15 · Tutorial
Likes (18)
Comment
Save
Tweet
Share
70.1K Views

Join the DZone community and get the full member experience.

Join For Free

An immutable object is an object that will not change its internal state after creation.

Immutable objects are very useful in multithreaded applications because they can be shared between threads without synchronization. 

Immutable objects are always thread safe.

Threads Are Everywhere

It is not important if you write explicit multithreaded application or not, often you work in a multithreaded environment without directly managing thread instances.

Here are few example of multithreaded applications where the programmer doesn't manually invoke the creation of new threads:

  • Web applications because servlets are handled by a pool of threads

  • Swing desktop applications where threads handle GUI events 

  • Timer instances create new threads to handle future task executions

Creating an Immutable Object

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

  • Don't add any setter method

  • Declare all fields final and private

  • If a field is a mutable object create defensive copies of it for getter methods

  • If a mutable object passed to the constructor must be assigned to a field create a defensive copy of it

  • Don't allow subclasses to override methods.

Now we discover point by point the reasons of the five rules explained before.

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.

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 reference 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. Here is an example showing an object with a private final field and an example on how to mutate its internal state:

public class DateContainer {
  private final Date date;

  public DateContainer() {
      this.date = new Date();
  }

  public Date getDate() {
    return date;
  }
}

....


  DateContainer dateContainer = new DateContainer();
  System.out.println(dateContainer.getDate());
  dateContainer.getDate().setTime(dateContainer.getDate().getTime() + 1000);
  System.out.println(dateContainer.getDate());
  // Now dateContainer date is 1 second after

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.

Here is the previous class with that modification:

public class DateContainer {
  private final Date date;

  public DateContainer() {
      this.date = new Date();
  }

  public Date getDate() {
    return new Date(date.getTime());
  }
}

....


  DateContainer dateContainer = new DateContainer();
  System.out.println(dateContainer.getDate());
  dateContainer.getDate().setTime(dateContainer.getDate().getTime() + 1000);
  System.out.println(dateContainer.getDate());
  // Now dateContainer date is not changed because we changed the copy, 
  // not the original date

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.

Here we show a modified example of DateContainer that accept a Date for the constructor and we will see how it is possible to change its internal state:

public class DateContainer {
  private final Date date;

  public DateContainer(Date date) {
      this.date = date;
  }

  public Date getDate() {
    return new Date(date.getTime());
  }
}

....

  Date date = new Date();
  DateContainer dateContainer = new DateContainer(date);
  System.out.println(dateContainer.getDate());
  date.setTime(date.getTime() + 1000);
  System.out.println(dateContainer.getDate());
  // Now dateContainer date is 1 second after also if the getter method
  // create a defensive copy of date. We changed the reference passed to the
  // constructor, not the copy.

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:

public class DateContainer {
  private final Date date;

  public DateContainer(Date date) {
      this.date = new Date(date.getTime());
  }

  public Date getDate() {
    return new Date(date.getTime());
  }
}

....

  Date date = new Date();
  DateContainer dateContainer = new DateContainer(date);
  System.out.println(dateContainer.getDate());
  date.setTime(date.getTime() + 1000);
  System.out.println(dateContainer.getDate());
  // Now dateContainer date is not changed. We create a copy on the constructor
  // so a change to the external date will not affect the internal state of
  // DateContainer instance

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. As an example of common immutable objects there are String, all primitive wrappers (Integer, Long, Double, Byte....), BigDecimal, BigInteger.

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:

  • Declare the immutable class as final so it can't be extended

  • Declare all methods of the immutable class final so they can't be overriden

  • 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!

Object (computer science) Java (programming language)

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

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

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

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 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook