Java Records

Jayamal Jayamaha
5 min readOct 24, 2022

Just Imagine

Before discussing what is the java record, let's imagine a scenario for a little time. think you need to call a database and get some data from a table, to do that you need an entity class. In this scenario, this entity class works as an object that get the data of a table in the database and carry that data throughout the application after data was fetched to that entity class.

To create that kind of entity class you need to write the following functionality in the class (Not necessary, but good to have)

  • Private final variables (Encapsulation and Immutability)
  • All args constructor
  • Getter methods
  • Override the toString() method (to print the object with values)
  • Override the equals() method (Compare the objects with other objects)
  • Override the hashCode() method (Will be used by equals method)

After writing all these things, the class would look like this.

public class Person {

private final String personId;
private final String name;
private final String address;

public Person(String personId, String name, String address) {
this.personId = personId;
this.name = name;
this.address = address;
}

public String getPersonId() {
return personId;
}

public String getName() {
return name;
}

public String getAddress() {
return address;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Person)) return false;
Person person = (Person) o;
return this.hashCode() == o.hashCode() &&
Objects.equals(personId, person.personId) &&
Objects.equals(name, person.name) &&
Objects.equals(address, person.address);
}

@Override
public int hashCode() {
return Objects.hash(personId, name, address);
}

@Override
public String toString() {
return "Person{" +
"personId='" + personId + '\'' +
", name='" + name + '\'' +
", address='" + address + '\'' +
'}';
}
}

this is a lot of code to write and maintain just for storing our data to use throughout our application. other than that there is not any specific functionality here, but just for carrying data. for this kind of class we call Data carrier classes

What are record classes

The issue described above was very annoying thing to developers. So in Java 14, the Record type was introduced. Record is a new kind of a type declaration. It gives the ability to define classes whose purpose is to store and carry data, with fewer lines of code.

It looks like the below after converting the above Person class into java Record.

public record Person(String personId, String name, String address) { }

This includes the following things

  • All args constructor
  • Getter methods for each field
  • toString() method
  • equals() method
  • hashCode() method

But everything in this universe is not perfect so there are some limitations in records as well

  • record classes are final, so you cannot extend other classes from the record class.
  • fields in record classes are also final, so you cannot set values after initializing the object.
  • Cannot declare extra fields in the body except the fields we declare in the record header.

At last, Record in java is a good and very usable feature that was introduced in java 14 if you want to implement and keep classes just for data carrier purposes.

Special features of Record classes

  • Java Record classes cannot be extended and also other classes cannot be extended by record class. it is final
  • Record classes can be implemented by one or more interfaces and their methods can be overridden in the Record class.
  • Cannot define other instance variables other than the fields that are defined in the header.
  • Can define our own methods and also our own constructor, but make sure that all the fields must be initialized in that constructor.
  • Records can be defined locally inside a method even like follows
public void someDummyMethod() {

record person(String personId, String name, String address){}

// dummy method logic
person person = new person("someId", "name", "address");
}

But we already have the Lombok library !!

Totally agreed. We can achieve the same thing which is done by records just using the Lombok library.

@AllArgsConstructor
@Getter
@ToString
@EqualsAndHashCode
public class Person {
private final String personId;
private final String name;
private final String address;
}

In the above example, the person class has.

  • Constructor with all arguments (@AllArgsConstructor)
  • Getter methods for all fields (@Getter)
  • toString() method (@ToString)
  • equals() method (@EqualsAndHashCode)
  • hashCode() method (@EqualsAndHashCode)

As you can see this is pretty much the same as java Record, isn’t it? Also, there is less code than the first time (Absolutely not like records. Records have fewer lines than this ). But then why the hell do we need java Records if we already have Lombok?

Well, actually there are some scenarios in which we may need to use java Records over Lombok, and also Lombok over java Records.

When to use What

When to use java Records

  • If you need a class just for data carrier purposes only
  • If all the data will definitely be available and you definitely initialize all the fields at the time of object creation.
  • If you don’t need to update the data inside the object from time to time, but just for read-only after initializing
  • If you need a data carrier object to store less amount of data (Probably less than 5 fields). If you have lots of data, then the header of the record class will be lengthy.
  • If you don’t need to extend other classes from the data carrier class or don’t need the data carrier class to be extended.
  • If you have the above requirements and don’t want to add extra weight by adding Lombok dependency

When to use Lombok

  • If you need to update data inside the object from time to time while accessing and transporting data throughout the application.
  • If you need to extend other classes from data carrier-class or data carrier-class need to be extended.
  • If you need to achieve a polymorphic behavior with your data carrier classes.
  • If you need a data carrier object to store lots of amount of data. Basically, you can use a builder pattern with Lombok as follows. very much useful if you have lots of data and if you need only a few fields to be initialized at the beginning.
Person person = Person.builder()
.personId("someId")
.name("name")
.address("address")
.build();
  • If data will be available for a few of the required fields at the time of object creation and then the rest of the fields at a later part, Lombok is a good choice because this can be achieved by @NotNull annotation and @RequiredArgsConstructor annotation.

--

--