Creating Effective Code using Java Records

Felix Coutinho - Jan 13 '23 - - Dev Community

Java Records is a new feature introduced in Java 14 to make it easier for developers to create immutable classes. A record is a special type of class (and a new keyword too) that acts as a data container or a data object, and it's used to hold a fixed set of values.

Let's check a short Java Records example.

record Point(int x, int y) {}
Enter fullscreen mode Exit fullscreen mode

This creates a new record class called Point, with two fields x and y. These fields are automatically marked as final, so they cannot be modified once the record is created.

Under the hood a few methods are going to be generated to help you, such as:

  • A constructor that initializes all the fields
  • Accessor methods (getters and setters) for each field
  • And toString, hashCode, and equals methods

This means that you don't have to write boilerplate code for these common tasks, making it much easier to create and maintain your code. And also by using Java Records you can eliminate a lot of use cases for the loved and hated Lombok library.

Why use Records?

The short answer is Records are more expressive, readable and faster than traditional DTO classes.

Using the example we already presented above, of a point in 2D space, you can easily use a record to clearly express that the class only has two fields and nothing else. Showing how readable and expressive record classes are.

DTOs vs Record

This is a inevitable comparison even though DTOs are not the only use case for Java Records. Both are used to hold a fixed set of values, but they have some key differences. When we compare Records with a DTO stylish class we can see a big difference in expressiveness and readability.

We can replace about 40 lines of code with 1 line only. Check the Point class written using the DTO pattern.

class PointDTO {

    private int x;

    private int y;

    public PointDTO(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    @Override
    public String toString() {
        return "PointDTO{" +
                "x=" + x +
                ", y=" + y +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        PointDTO pointDTO = (PointDTO) o;
        return x == pointDTO.x &&
                y == pointDTO.y;
    }

    @Override
    public int hashCode() {
        return Objects.hash(x, y);
    }
}
Enter fullscreen mode Exit fullscreen mode

As you can see, compared to the Record class, the DTO class contains a lot more code (boilerplate code), including the constructor, getter methods, and the methods toString, hashCode, and equals which are common to most DTOs.

  • Unlike DTOs, records are immutable by nature, meaning their fields cannot be modified once the record is created. This makes records more suitable for functional programming and improves code safety.
  • Records have built-in support for common methods like toString, hashCode, and equals, which eliminates the need for boilerplate code.
  • Records are a more modern and expressive way of creating data classes compared to DTOs, which could make it easier for new developers to read and understand the codebase.

And we can point out more reasons to use Records.

JVM loves Records (and vice versa)

Java Records are more efficient than traditional classes in terms of memory usage and performance because of their immutable nature, the way they are implemented in the JVM, and the techniques like compacting and inlining that the JVM can apply to classes markes as records.

Records eliminate the need for defensive copying (check Guideline 6-2), which can improve performance by reducing the number of operations that need to be performed on the data.

Because Records don't have any additional methods or fields, the JVM can use more aggressive optimization techniques for records, like inlining (check Phase 1), that can further improve performance. But, it doesn't mean more methods can be added, you still can adding more methods as you need.

Disadvantages of using Records

As with everything in life (technology especially), there are also some drawbacks when using records.

Java Records are not suitable for use as JPA (Java Persistence API) entity classes because they have some limitations that make them incompatible with the requirements of JPA entities.

  • JPA entities are required to have a no-arg constructor, which is not provided by default for records. This means that you would have to manually add a no-arg constructor to the record class, which would defeat the purpose of using a record in the first place.
  • JPA entities are required to have setter methods for each field so that the entity manager can update the fields in the database. However, records do not have setter methods by default, as their fields are automatically marked as final.
  • JPA entities can have additional methods and fields that are not part of the record.
  • JPA entities can be extended or implemented interfaces or classes, while records cannot.

As you can see while records provide a concise and efficient way to create immutable classes, they are not suitable for use as JPA entities due to the limitations on constructors, setter methods, additional methods, fields and interfaces or classes that JPA entities require.

To wrap up

When I first saw Records my thought was to replace all of my DTOs and JPA Entities with Records right away but I was partially wrong. Clearly, DTOs and data classes are good candidates to be replaced by Records but not our lovely and long JPA Entities because of the limitation we discussed here.

One more time writing and diving into concepts I like such as Records made me more confident to make choices about whether recommend or not Records for my Java projects or even better to refactor or not to use Records. And due to the simple use and low cost of Records it can be used in different parts of a Java codebase and not blocking you to use other type of classes such as Entities in different parts of the code base.

What about you? Are you using Records in your projects? How is the experience so far?

. . . . . . .
Terabox Video Player