The Record feature is part of the Project Amber, an effort to explore and incubate smaller, productivity-oriented Java features. This feature was introduced in Java 14 and is going being improved step by steps. For release 20, e.g, you can see here.

A record class is a shallowly immutable, transparent carrier for a fixed set of values, called the record components [1]

The Record is a class type in java to be used to data carrier. It has:

  • canonical constructor (same accessibility of the record)
  • private final fields
  • Getters methods for each field
  • Equals method
  • HashCode method
  • ToString method.

The responsibility for creating all these methods lies with Java Compiler. All these methods can be override.


How to use the record

The records are a implementation of the Value Object pattern where the instances are imutable. They don't use the bean conventions using "get" in the methods to access the attributes.

To create a record is necessary to use the keyword record and declare the attributes. The compiler will create the methods to access the attributes (Getters), all-arguments constructor, toString, equals, hashCode. Pay attention that the Setters will not be created. Furthermore, this class cannot have subclass because it is marked as final class.

record FirstRecord (int att1, String att2, double att3, Object att4){
}

public class MyFirstRecord {

  public static void main(String[] args) {

    FirstRecord fr = new FirstRecord(1, "abc", 0, null);

    System.out.println(fr.att1());
    System.out.println(fr.att2());
    System.out.println(fr.att3());
    System.out.println(fr.att4());
    System.out.println(fr);
  }
}

# Console
1
abc
0.0
null
FirstRecord[att1=1, att2=abc, att3=0.0, att4=null]

Even though the record gives the constructor, it can be explicit for some validation purposes. In the same way, it's possible to create a non-arg constructor (not recommended). For non-arg constructor, you have to call explicitly the arg-constructor anyway. To a canonical contructor is not necessary call the arg-constructor. In case of add new attribute, it should be static.

// With non-args
record FirstRecord (int att1, String att2, double att3, Object att4){

  static String newAtt;

  FirstRecord() {
    this (0, "", 0, null);
  }
}

// #With canonical
record FirstRecord (int att1, String att2, double att3, Object att4){

  public FirstRecord {
    if (att2 == null) {
       throw new IllegalArgumentException("attr2 cannot be null");
    }
  }
}

The record support generics and annotations. It also support instance methods and static methods.

record FirstRecord<T> (@Transient Long att1, String att2, T att){
  public String process() {
    return "Att2: " + att2;
  }
  public static void test(FirstRecord myRecord) {
      System.out.println(myRecord.att1);
  }
}

MyRecord<Integer> fr = new MyRecord<>(1L, "test", 2);

System.out.println(fr.process());
FirstRecord.test(fr);

Another point is that Records can implement interfaces (implements) but cannot extend other records.


When to use the record

It is indicated to use as domain model class or data transfer objects, e.g, when it's not necessary to change the values.

However, it can be painful in cases where you have many attributes and most of then are null.

The record is flexible to be customized. However, if you need to do this a lot, maybe the record is not the best option for you.


Record vc Lombok

Lombok is a external library to auto-generate some common patterns avoiding boilerplate. It helps to create immutable objects with @Value annotation. Lombok is more mature and is more flexible. Also, lombok can add some validations to validate fields. Beside,it has @Data annotation if is necessary change data. Another good point is the fact that Lombok can use the @Builder annotation to facilitate the object creation.

Analysis by cases:

  1. Classes with many fields
    • Record: instantiation can be hard especially if some of the fields aren't mandatory (better for smaller objects)
    • Lombok: provides implementation of the Builder design pattern
  2. Mutable Data
    • Record is exclusively for immutable data. Not inficate for frameworks that require Setters methods (as hibernate)
    • Lombok can use @Data to be mutable. When creating an @Entity, Lombok can be a better choice.
  3. Inheritance
    • Record do not support inheritance.
    • Lombok can use @Data objects that can both extend other classes and be extended.


Conclusion

Lombok is the best option for many scenarios. However, it's good override it as soon as possible. The plans are to improve the record for each version.


References