Migrating From Lombok to Records in Java
Below article covers the process of migration from Lombok to Records.
Join the DZone community and get the full member experience.
Join For FreeJava, as a programming language, has evolved over the years, introducing new features and improvements to enhance developer productivity and code readability. With the release of Java 14, one notable feature is the introduction of records as a language feature, offering a concise way to define immutable data-carrying classes.
If you have been using Lombok to reduce boilerplate code in your Java classes, it's worth considering migrating to records for a more native and standardized approach.
In this article, we will explore the process of migrating Java code with Lombok to Java records, using practical examples.
Why Migrate From Lombok to Records?
Lombok has been widely adopted in the Java community for its ability to reduce verbosity by automatically generating getters, setters, constructors, and other repetitive code. While Lombok is effective, the introduction of records provides a standardized and built-in solution for defining immutable data classes. Records offer better integration with the language and are supported natively by various tools and frameworks.
Migrating Getters and Setters
Lombok Example
import lombok.Data;
@Data
public class Movie {
private String title;
private int releaseYear;
}
Record Example
public record Movie(String title, int releaseYear) {
}
In the record example, we define a Movie class with two fields (title and releaseYear) in the constructor parameter list. The compiler automatically generates the constructor, equals(), hashCode(), and toString() methods, which are similar to what Lombok would generate.
Migrating Constructors
Lombok Example
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
@AllArgsConstructor
@NoArgsConstructor
public class Series {
private String title;
private int startYear;
private int endYear;
}
Record Example
public record Series(String title, int startYear, int endYear) {
}
Records automatically generate a compact and expressive constructor that initializes all fields. In the Series record example, the constructor takes three parameters corresponding to the fields title, startYear, and endYear.
Immutable Records
Lombok Example
import lombok.Value;
@Value
public class Actor {
private String name;
private int birthYear;
}
Record Example
public record Actor(String name, int birthYear) {
}
Records inherently provide immutability, as all fields are marked as final by default. In the record example for the Actor class, the name and birthYear fields are immutable, and no setters are generated.
Handling Default Values
Sometimes, it's necessary to handle default values for certain fields. In Lombok, this can be achieved using @Builder or custom methods. With records, default values can be set directly in the constructor.
Lombok Example
import lombok.Builder;
@Builder
public class Film {
private String title;
private String director;
private int releaseYear;
}
Record Example
public record Film(String title, String director, int releaseYear) {
public Film {
if (Objects.isNull(title)) {
this.title = "Unknown Title";
}
if (Objects.isNull(director)) {
this.director = "Unknown Director";
}
}
}
In the record example for the Film class, default values are set directly in the constructor body. If the title or director is null, default values are assigned.
Using Builder With Lombok
import lombok.Builder;
@Builder
public class FilmWithLombok {
private String title;
private String director;
private int releaseYear;
}
// Example of using the builder:
FilmWithLombok film = FilmWithLombok
.builder()
.title("Inception")
.director("Christopher Nolan")
.releaseYear(2010)
.build();
In the Lombok example, the @Builder annotation generates a builder class for the FilmWithLombok class. The builder provides a fluent API for constructing instances with optional and chainable setter methods.
Using Builder With Java Record
public record FilmWithRecord(String title, String director, int releaseYear) {
public static class Builder {
private String title;
private String director;
private int releaseYear;
public Builder title(String title) {
this.title = title;
return this;
}
public Builder director(String director) {
this.director = director;
return this;
}
public Builder releaseYear(int releaseYear) {
this.releaseYear = releaseYear;
return this;
}
public FilmWithRecord build() {
return new FilmWithRecord(title, director, releaseYear);
}
}
}
// Example of using the builder:
FilmWithRecord film = new FilmWithRecord
.Builder()
.title("The Dark Knight")
.director("Christopher Nolan")
.releaseYear(2008)
.build();
For Java records, we create a static nested Builder class within the record. The builder class has methods for setting each field and a build method to create an instance of the record. This provides a similar fluent API as seen in the Lombok example.
Using builders with records or Lombok provides a convenient and readable way to construct instances, especially when dealing with classes with multiple fields. Choose the approach that aligns with your preferences and project requirements.
Conclusion
Migrating from Lombok to Java records is a step towards leveraging native language features for better code maintainability and readability.
Records provide a standardized and concise way to define immutable data classes, eliminating the need for additional libraries like Lombok. By following the examples provided in this article, developers can seamlessly transition their code to benefit from the latest language features in Java 14+. Remember to update your build configuration and dependencies accordingly, and enjoy the enhanced expressiveness and simplicity offered by Java records.
Opinions expressed by DZone contributors are their own.
Comments