Java Records: Is it really Immutable?


Last mail was about 'How to Use Java Records to Write Better and More Efficient Code'.

But Is it really Immutable?

Java often receives criticism for being too formal, requiring developers to write a lot of code even for simple tasks. It has some good sides like, it making Java code more readable and at the same time helping the developer to write code that has fewer bugs. In some instances, however, it creates unnecessary overhead. The worst case scenario is when there is a need for a data career class that holds some immutable data and does not need to perform any action other than holding these data. To write this type of class the developers need to write lots of code that is repetitive and error-prone, such as constructors, accessors, equals, hashCode, and toString methods. Often the developer has to take shortcuts, like not writing important methods, or using a different class that’s not really right for the job. This can lead to problems like unexpected behavior or making it hard to debug the code.

Of course, IDE can be used to generate the boilerplate code but it does not always make the developer's life easy! Imagine the case, where two or three new fields are added. In this case, we need to regenerate all of the accessors, constructors, toString, and other necessary codes.

IDEs (computer programs for coding) can be used to generate the boilerplate code in a class that holds data. However, they don’t make it easier for someone reading the code to understand the main idea of “I’m a container for data about x and y” when there are many lines of repetitive code. To simplify the development process, Java code that models a small number of values should be simpler to write, understand, and verify.

To address this issue Java team has introduced Record. Java Record is basically a restricted form of class like an enum.

According to OpenJDK 16 documentation, the purpose of Java record is to:

Enhance the Java programming language with records, which are classes that act as transparent carriers for immutable data. Records can be thought of as nominal tuples.

But now the question is

IS IT REALLY IMMUTABLE?

In the article, we’ll take a really close look at this issue to help you understand it better. We want to explain if the thing we’re talking about is actually unchangeable like it says it is.

Let’s consider an example: a record for ‘User’. For our purposes, let’s assume that the User record only holds the user’s first name and last name.

public record User(String firstName, String lastName) {
}

Now we can use this in our code like this:

public static void main(String[] args) {
User user = new User("John", "Doe");
System.out.println(user);
}

If we run this code we will get the following output in our console:

User[firstName=John, lastName=Doe]

We can even get the value of the individual field like this:

// Get First Name
user.firstName();

// Get Last Name
user.lastName()

The record doesn’t offer any method to change the data it holds. This gives the impression of immutability.

Suppose we need to add the user's email address. how can we do this? Simple. Just add an email field in the record.

public record User(String firstName, String lastName, String email) {
}

Again, we can initialize it like below:

User user = new User("John", "Doe", "john@doe.com");

Now, let’s make a few changes. Let’s think about the possibility that our customers could have more than one email address. To accommodate this, we can modify the email data type from a single string to a list of emails, like this:

public record User(String firstName, String lastName, List
}

Now, let's initialize our user record:

public static void main(String[] args) {

List
emailAddress.add("john@doe.com");
emailAddress.add("john02@test.com");
User user = new User("John", "Doe", emailAddress);
}

Executing this will display the following output in the console:

User[firstName=John, lastName=Doe, emailAddress=[john@doe.com, john02@test.com]]

We can retrieve email addresses like this (where the index represents the position of the element in the list):

user.emailAddress().get(index)

now consider the following code:

user.emailAddress().add("john03@gmail.com");

Let’s incorporate it within our main method and display the resulting output. Observing the outcome:

public static void main(String[] args) {

List
emailAddress.add("john@doe.com");
emailAddress.add("john02@test.com");
User user = new User("John", "Doe", emailAddress);

// Add new item to the email address list
user.emailAddress().add("john03@gmail.com");

System.out.println(user);

}

The output is:

User[firstName=John, lastName=Doe, emailAddress=[john@doe.com, john@test.com, john03@gmail.com]]

Take a closer look at the email address. Even though we said the Record is immutable, we’re actually able to change the list of email addresses in this situation!

The same situation will happen if we use other mutable data, like Maps and Sets.

This brings us to our main question: Can the Record actually be changed?

The answer is: NO

The Java Record is not truly mutable. However, by using it wisely and selecting appropriate data types, we can make it immutable.

Java Records provides a method for managing data with the promise of immutability. Although it may seem possible to alter certain aspects of a Record, its core cannot be altered. By using Records intelligently, we can improve code readability and reliability, thereby simplifying Java data management.

Thank you for your time.

Learn With Iftekhar

I’m Iftekhar — a developer sharing what I learn about Java, Spring Boot, Spring Security, and related backend technologies like Docker, Kubernetes, and Kafka.Each week, I send one practical email with code examples, mini-projects, and real-world lessons to help you grow as a backend developer.

Read more from Learn With Iftekhar

Monday morning, I was sipping coffee. On my desk. in my office Sarah, along with another Junior Developer, Tom, came to me. "Service works on my laptop. Crashes in staging. Same code. No idea why!" - Said Tom I checked the log. in the staging: ERROR - No qualifying bean of type 'EmailService' available ERROR - expected at least 1 bean which qualifies as autowire candidate But Tom's Local logs: INFO - Started Application in 8.2 seconds INFO - EmailService initialized successfully Same code....

It was 3 am. Cold night. I was in deep sleep. That's when Sarah called me. "Payment service down. It's 500 errors!!" I was terrified. Customers couldn't buy anything. My sleep... just gone. I opened my computer.... Logged on to the server to see what happened. The log showed: ERROR - BeanCreationException: Error creating bean 'paymentProcessor' ERROR - Could not resolve placeholder 'stripe.api.secret' I was exhausted. After a loooong week of development, I just wanted to take some rest. but...

How to Use Java Records to Write Better and More Efficient Code JAVA is one of the most popular and widely used programming languages. In many cases, it is the first choice for enterprise application development. Even now billions of devices are powered by JAVA. If you are reading this article on your Android — you got it! This is also run by JAVA! Oracle, the company who is responsible for developing and maintaining the JAVA language itself, introduces new features on a regular basis to make...