Java record class & Lombok
Introduction
Section titled āIntroductionāPassing immutable data between objects is very common in Java. With the release of Java 14, you can use records to perform this task.
Very often you write classes that hold data such as query results or service information. In many cases, this data is immutable. Immutability ensures the validity of the data without synchronization.
since the internal state of an immutable object remains constant in time, you can share it among multiple threads.
To accomplish immutability, you must create data classes with the following constraints:
private,finalfield for each piece of data,- getter for each field,
publicconstructor with an argument for each field,equals()method that returnstruefor objects of the same class when all fields match,hashCode()method that returns the same value when all fields match,toString()method that includes the name of the class and the name of each field and its corresponding value
Letās create a simple Dog class with age and name:
public class Dog {
private final String name; private final int age;
public Dog(String name, int age) { this.name = name; this.age = age; }
@Override public int hashCode() { return Objects.hash(name, age); }
@Override public boolean equals(Object obj) { if (this == obj) { return true; } else if (!(obj instanceof Dog)) { return false; } else { Dog other = (Dog) obj; return Objects.equals(name, other.name) && Objects.equals(age, other.age); } }
@Override public String toString() { return "Dog [name=" + name + ", age=" + age + "]"; }
// getters
public String getName() { return this.name; }
public int getAge() { return this.age; }}As you can see, thereās a lot of boilerplate code. All the extra code obscures that the class is simply a data class with two fields.
Write a record class
Section titled āWrite a record classāAs of JDK 14, you can replace repetitious data classes with records. Records are immutable data classes that require only the type and name of fields.
The equals(), hashCode(), and toString() methods, the private final fields and public constructor are generated by the Java compiler.
Letās create the same Dog class with age and name:
public record class Dog {String name, int age) {}Record class VS Lombok
Section titled āRecord class VS LombokāLetās take the Color object as example.
It has three integer values representation the RGB channels: red, green, blue.
The Color also expose its HEX representation.
Moreover, two Color objects are equals if they have the same RGB values.
public record Color(int red, int green, int blue) { public String getHexString() { return String.format("#%02X%02X%02X", red, green, blue); }}Lombok allows you to create immutable objects using the @Value annotation:
@Valuepublic class ColorValueObj { int red; int green; int blue;
public String getHexString() { return String.format("#%02X%02X%02X", red, green, blue); }}JEP 359 states that records are classes that act as transparent carriers for immutable data. As a result, you canāt stop a record from exposing its member fields.
Lombok allows you to customize the names, access levels, and return types of the getters.
Letās update the ColorValueObj accordingly:
@Value@Getter(AccessLevel.NONE)public class ColorValueObject { int red; int green; int blue;
public String getHexString() { return String.format("#%02X%02X%02X", red, green, blue); }}Records are a good solution for immutable data objects. If you want to hide the member fields and only expose some operations performed using them, Lombok will be better suited.
Classes with many fields
Section titled āClasses with many fieldsāLetās take a look at a record where the data model requires more fields.
public record EmployeeRecord( String firstName, String lastName, Long employeeId, String email, String phoneNumber, String address, int age) {}The instantiation of EmployeeRecord could be hard to read, especially if some fields could be left null:
To facilitate these use-cases, Lombok provides an implementation of the Builder design pattern.
In order to use it, you need to annotate a class with @Builder:
@Getter@Builderpublic class EmployeeBuilder { private String firstName; private String lastName; private Long employeeId; private String email; private String phoneNumber; private String address; private int age;}Letās use EmployeeBuilder to create an object with the same attributes:
EmployeeBuilder john = EmployeeBuilder.builder() .firstName("John") .lastName("Doe") .email("john@doe.com") .age(25) .build();Records are better for smaller objects. For objects with many fields, the lack of creation patterns will make Lombokās
@Buildera better option.
Mutable data
Section titled āMutable dataāYou can use java records exclusively for immutable data.
If the context requires a mutable java object, you can use Lombokās @Data object instead.
@Data@AllArgsConstructorpublic class ColorData { private int red; private int green; private int blue;
public String getHexString() { return String.format("#%02X%02X%02X", red, green, blue); }}Inheritance
Section titled āInheritanceāJava records do not support inheritance.
They cannot be extended or inherit other classes.
On the other hand, Lombokās @Value objects can extend other classes, but they are final:
@Valuepublic class MonochromeColor extends ColorData {
public MonochromeColor(int grayScale) { super(grayScale, grayScale, grayScale); }}
@Dataobjects can both extend other classes and be extended.