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