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
Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
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

Integrating PostgreSQL Databases with ANF: Join this workshop to learn how to create a PostgreSQL server using Instaclustr’s managed service

Mobile Database Essentials: Assess data needs, storage requirements, and more when leveraging databases for cloud and edge applications.

Monitoring and Observability for LLMs: Datadog and Google Cloud discuss how to achieve optimal AI model performance.

Automated Testing: The latest on architecture, TDD, and the benefits of AI and low-code tools.

Related

  • Visualizing Thread-Safe Singletons in Java
  • Double-Checked Locking Design Pattern in Java
  • Java: How Object Reuse Can Reduce Latency and Improve Performance
  • Java: Creating Terabyte Sized Queues with Low-Latency

Trending

  • Docker and Kubernetes Transforming Modern Deployment
  • Scalable Rate Limiting in Java With Code Examples: Managing Multiple Instances
  • LLMs for Bad Content Detection: Pros and Cons
  • LTS JDK 21 Features
  1. DZone
  2. Software Design and Architecture
  3. Integration
  4. The Importance of Immutability in Java

The Importance of Immutability in Java

We all know immutability is important, but do you know why or how to achieve it in Java? This post is a one stop shop guide to the challenge.

Sam Atkinson user avatar by
Sam Atkinson
·
Apr. 05, 16 · Opinion
Like (27)
Save
Tweet
Share
35.11K Views

Join the DZone community and get the full member experience.

Join For Free

One of the consistent criticisms of Java is that it lacks a formal immutable type. We can (and should) make a good attempt at creating immutable Objects, even though they may be inherently flawed due to the nature of the JVM.

An immutable object is one whose state cannot and will not change after it’s initial creation. Immutable objects are great, mostly because they are Thread safe (and threaded code should be avoided as much as possible). You can pass them around without fear they will be changed. I highly recommend you spend some time with a functional language like Scala to really appreciate the amazing power immutable Objects can have (but then come straight back, because Scala has a whole different bag of problems).

Interestingly, almost all of the new features in Java 8 (Date and Time, Optionals and Streams) have been implemented in an immutable fashion. This allows much of the performance benefits that can come from things such as parallel Streams. Immutable Objects allow us to create side-effect free functions as seen in Functional Programming languages which are the basis for creating fast, lock free code.

How to Create an Immutable Object in Java?

The main action is to mark all fields as final. This obviously means they cannot change after initial construction. Beware though, that you can still have a final field where the Object contained is mutable. In this case it is necessary to copy the Object when initially set in the constructor, and provide a copy of the Object when it is being accessed from outside the class.

This obviously adds complication to our code and design. Ideally you should follow the original advice from Effective Java:

"Classes should be immutable unless there's a very good reason to make them mutable....If a class cannot be made immutable, limit its mutability as much as possible."

If you have an Object field in your class endeavour where possible to make it immutable too.

If you succeed in making all your fields immutable then you may choose to also make them public as I do- the fields cannot be changed post construction and are only used for reading. This makes the addition of a getter redundant. In my code bases if I’m accessing data using the fields then I know that class is Immutable. The main exception to this is when I’m writing libraries, as it’s much harder to refactor if you need to introduce mutability later on. If you own all the code though, to move from field access to method access is one shortcut in IntelliJ.

You should also make your class final to defend from subclassing. It would be possible to create mutable subclasses and thus ruining your hard work.

It takes a concious effort to create immutable classes but it should be your target wherever possible. A common anti-pattern I’ve seen in developers is that after creating a constructor and set of fields they generate getters/setters for all of them. Do not do this! Firstly, code should only be written if it is needed; if you have no test or prod code that is accessing a field then it does not need a getter; if no other code is trying to change the field after creation then you don’t need a setter. Create code on demand and do not optomize early.

One of the main criticisms of immutable objects is that it can lead to a proliferation of objects and as a result performance issues- have the potential for a significant amount of churn of new objects as you’re having to create a new one for any state change.  Unless you're in a crazy high performance environment (and you're almost certainly not) then it really isn't an issue.  Objects are cheap. Even Oracle thinks so:

“The impact of object creation is often overestimated and can be offset by some of the efficiency associated with immutable objects. These include decreased overhead due to garbage collection, and the elimination of code needed to protect mutable objects from corruption.”

This is a classic case of eagerly optomising code. If you create immutable code and it turns out you’re hitting massive performance roadblocks then refactor. For most cases you’ll be fine. There are obvious exceptions; data structures tend to be much easier to implement and more performant if using mutability. As always, apply common sense to your approach, but default to immutability.

Java (programming language) Threading

Opinions expressed by DZone contributors are their own.

Related

  • Visualizing Thread-Safe Singletons in Java
  • Double-Checked Locking Design Pattern in Java
  • Java: How Object Reuse Can Reduce Latency and Improve Performance
  • Java: Creating Terabyte Sized Queues with Low-Latency

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • 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: