Java Classes formed the basis of whatever Object Oriented Programming we have been doing prior to the introduction of Functional Programming with Java 8 which gave a new perspective to how we program in Java.
Java has come a long way in terms of the features that it offers as well as coping up with new requirements and functionality being offered by other VM & non VM based programming languages.
When it comes to Java, one of the things that most of the people like to talk about is Immutability & the Ceremony around creating the classes and it associated attributes and accessors.
Even though Java offers ways to achieve Immutability, the onus was left to the programmer to properly design the classes using the constructs that Java offers. Scala for example has been build with Immutability as the very first design principle.
When it comes to the ceremony and boiler plate code in Java, it has been reduced considerably with the introduction of the Streams & Functional Programming introduced along with Java 8, but there has still been scope for improvement along this area.
In this particular article we are gonna talk about a new feature that has been made available as part of Java 16 called as Records which help us to achieve Immutability as well as reduce the boiler plate code and the verbosity that we had to go over even for our simplest classes. Let us go ahead and explore more details around Records and see what it has to offer.
Java came up with the concept of Records as a preview in Java 14, which was put for a 2nd preview in Java 15 and finally made available as a feature in Java 16.
The details over the proposal and its finalization can be further referred to from the following location :
https://openjdk.java.net/jeps/395
The relevant documentation can be referenced from the following link:
https://docs.oracle.com/en/java/javase/16/language/records.html
This is just an introduction to the topic and further details can be explored by visiting the above mentioned links.
Use Case
Let us consider an example to better understand how Records makes our life easier and things that is has to offer against the Classes that we have been using so far.
Let us take a simple data/pojo class called Employee which has the following fields:
- empId
- firstName
- lastName
When we create a domain/data class for an Employee whose instances we want to make Immutable, we generally do the following things:
- create private instance variables/fields(even mark them as final for Immutability)
- create a constructor to initialize these fields
- create setters & getters for these fields
- override the equals(), hashcode() & toString()
Let us go over the code snippets :
Employee.java
package com.kapil.java16;
import java.util.Objects;
public final class Employee {
private final Long empId;
private final String firstName;
private final String lastName;
public Employee(Long empId, String firstName, String lastName) {
this.empId = empId;
this.firstName = firstName;
this.lastName = lastName;
}
public Long getEmpId() {
return empId;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
@Override
public boolean equals(Object obj) {
if (obj == this) return true;
if (obj == null || obj.getClass() != this.getClass()) return false;
var that = (Employee) obj;
return Objects.equals(this.empId, that.empId) &&
Objects.equals(this.firstName, that.firstName) &&
Objects.equals(this.lastName, that.lastName);
}
@Override
public int hashCode() {
return Objects.hash(empId, firstName, lastName);
}
@Override
public String toString() {
return "Employee[" +
"empId=" + empId + ", " +
"firstName=" + firstName + ", " +
"lastName=" + lastName + ']';
}
}
Thus we see that a lot of boiler plate code is needed before we can actually start using our domain entity. There have been some workaround for this by auto generating the code via IDE using Annotations via project Lombok. But it would have been good if Java itself provided us with this feature.
Records to the rescue. Let us now see how we can achieve the very same thing by using Records offered as part of Java 16.
package com.kapil.java16;
public record Employee(Long empId, String firstName, String lastName) {
}
Well, that’s all that is needed.
People who are familiar with Scala might relate that something very similar is already offered by Scala referred to as Case Classes.
To create an Employee record in our code, all we need to do is instantiate like we do normally with our classes using the new Operator, as Records are a special kind of class offering Immutability and concise code.
package com.kapil.java16;
public class RecordSample {
public static void main(String[] args) {
Employee employee1 = new Employee(1L, "Ankit" , "P");
Employee employee2 = new Employee(1L, "Amit" , "S");
System.out.println(employee1);
System.out.println(employee2);
}
}
Output :

Thus Records offers us the following benefits :
- Internally creates final private instance variables for the attributes specified as part of the Record declaration
- Creates a constructor whose signature is same as that of the Record
- public accessors for the instance variables defined in the record declaration
- Implementation for the equals(), hashcode() & toString()
Thus we see that Record takes care of all the boiler plate code as well as makes the class Immutable as they are final. Whatever initialization has to be done is done as part of the instance creation. We can define our own methods within the record body if we wish to. There are other specific features and corner cases for Records that are not covered as port of this post. Maybe I’ll cover it in a separate post.
So that’s it for this post. Go ahead and run this piece of code in your favorite java editor.
See you until next time. Happy Learning !