Records are not “Lombok-lite”
Recreating Lombok is not the purpose of Java record.
The purpose of Java record is to provide an explicit vehicle for transparently communicating shallowly-immutable data.
Technically, records are Java’s nominal tuple. Tuple means an ordered set of fields. Nominal means the fields have names, as does their container. Practically, you can think of a Java record as a struct on steroids.
See the official document for scope and purpose, JEP 395: Records.
So no Builder feature need be provided by default as that lies outside the scope of Java record. However, you can easily create your own Builder for any particular record class.
AI-generated
Actually, you need not write your own Builder implementation. Let a generative AI draft the code on your behalf. (Be sure to review carefully as these AIs are imperfect.)
For example:
write code for a Builder class for the Java record
record Person ( String name , LocalDate birth ){}
Ecosia AI chat feature produces:
public record Person(String name, LocalDate birth) {
public static class Builder {
private String name;
private LocalDate birth;
public Builder name(String name) {
this.name = name;
return this;
}
public Builder birth(LocalDate birth) {
this.birth = birth;
return this;
}
public Person build() {
return new Person(name, birth);
}
}
}
That code worked for me, copy-pasted, with no edits needed.
Usage:
Person person = new Person.Builder()
.birth(LocalDate.of(2001, Month.JANUARY, 23))
.name("Alice")
.build();
person.toString() // ➡️ Person[name=Alice, birth=2001-01-23]
Withers
By the way, work is underway to add “withers”, a feature to instantiate a new record object based on the payload values of another. See JEP 468: Derived Record Creation (Preview).
Jakarta Validation
You may want to use Jakarta Validation (previously known as Bean Validation) to verify the validity of your new record object’s state.
Likewise, you might use Jakarta Validation in your Builder implementation.
IDE code generation
Your IDE may have a feature for generating code for a Builder from a given Java Record.
For example, IntelliJ has a built-in feature Replace Constructor with Builder. However that does not work for Java Record. But there is a plugin for that. The Record Builder Plugin can “automatically generate builder classes for your Java Records, JavaBeans and Interfaces, allowing you to select fields and configure the generated builder”.
RecordBuilder library
RecordBuilder is an interesting project that lets you mark a Java record with an annotation. Then RecordBuilder generates code for builders and withers.
I’ve not yet tried using this library, so I cannot vouch for it.
Answer from Basil Bourque on Stack OverflowVideos
Is it worth using the Builder pattern with Java Records, or does it defeat the purpose of using Records in the first place? I'm trying to decide if I should combine these two, especially for scenarios where I have optional fields. Any advice or best practices?