On this page
Builder
The Builder pattern constructs complex objects step by step, separating construction from representation.
Problem
Constructing an object with many optional parameters leads to telescoping constructors or setters that leave objects in invalid states.
Solution
public class Pizza {
private final String size;
private final boolean cheese;
private final boolean pepperoni;
private final boolean mushrooms;
private Pizza(Builder builder) {
this.size = builder.size;
this.cheese = builder.cheese;
this.pepperoni = builder.pepperoni;
this.mushrooms = builder.mushrooms;
}
public static class Builder {
private String size = "medium";
private boolean cheese = true;
private boolean pepperoni = false;
private boolean mushrooms = false;
public Builder size(String size) {
this.size = size;
return this;
}
public Builder cheese(boolean cheese) {
this.cheese = cheese;
return this;
}
public Builder pepperoni(boolean pepperoni) {
this.pepperoni = pepperoni;
return this;
}
public Builder mushrooms(boolean mushrooms) {
this.mushrooms = mushrooms;
return this;
}
public Pizza build() {
return new Pizza(this);
}
}
}
// Usage
Pizza pizza = new Pizza.Builder()
.size("large")
.pepperoni(true)
.mushrooms(true)
.build();
Lombok @Builder
@Builder
public class User {
private final String name;
private final String email;
@Builder.Default
private final String role = "USER";
}
User user = User.builder()
.name("Alice")
.email("[email protected]")
.build();
Java Standard Library
StringBuilder sb = new StringBuilder()
.append("Hello")
.append(" ")
.append("World");
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com"))
.header("Accept", "application/json")
.GET()
.build();
Stream.builder()
.add(1).add(2).add(3)
.build();
Builder vs Constructor
| Builder | Constructor |
|---|---|
| Many optional parameters | Few required parameters |
| Fluent, readable API | Simple creation |
| Immutable result | Can be mutable |
| Step-by-step validation | All-or-nothing |
When to Use
- Object has 4+ constructor parameters, many optional
- You want an immutable object with optional fields
- Step-by-step construction with validation at build time
Best Practices
- Make the built object immutable
- Validate in
build()— throw if required fields are missing - Use
@Builder(Lombok) or records with compact constructors for simple cases - Consider static factory methods for objects with few parameters