Builder Pattern in Java (with Example)
The Builder pattern explained: construct an object with many optional fields step by step via a fluent chain and build(), avoiding telescoping constructors and getting an immutable result. Java code, UML, when to use.
🟢 Design Patterns · Creational · Fresher → 🟠senior
The Builder pattern solves an everyday annoyance: constructing an object that has lots of fields, many of them optional. Without it you end up with monster constructors like new User("Sam", null, null, 30, null, true, null) — unreadable and error-prone. Builder lets you construct the object step by step with a clean, fluent, self-describing syntax.
build() to get the finished, immutable object.
The problem: the telescoping constructor
Say a Pizza has size, cheese, pepperoni, mushrooms, olives, crust type… Most are optional. You end up either writing many overloaded constructors (the "telescoping constructor" anti-pattern) or one giant constructor where callers pass a confusing string of true, false, null, null. Both are hard to read and easy to get wrong — swap two boolean args and nothing complains.
The solution: a fluent builder
🟠Give the class a static Builder with a method per optional field that returns the builder itself (so calls chain), and a final build():
Pizza p = new Pizza.Builder("Large") // required arg in ctor
.cheese(true)
.mushrooms(true)
.olives(false)
.build(); // returns the finished Pizza
// the builder:
class Pizza {
private final String size; private final boolean cheese, mushrooms;
private Pizza(Builder b){ size=b.size; cheese=b.cheese; mushrooms=b.mushrooms; }
static class Builder {
private final String size; // required
private boolean cheese, mushrooms; // optional, default false
Builder(String size){ this.size = size; }
Builder cheese(boolean v){ this.cheese=v; return this; } // chain
Builder mushrooms(boolean v){ this.mushrooms=v; return this; }
Pizza build(){ return new Pizza(this); }
}
}
Each call reads like plain English, only the fields you care about are set, and the result can be immutable (all-final fields, no setters) — which is a big win for safety and thread-safety. You can also validate in build() before creating the object.
You've already used it
🟠Java's StringBuilder (.append().append().toString()) is the Builder idea, and libraries everywhere use it — StringBuilder, Stream.Builder, HTTP client request builders, Lombok's @Builder. Recognising "this is just Builder" in familiar APIs is a nice thing to point out.
When to use it
🟠Reach for Builder when an object has many parameters, several optional, or when you want the result immutable and constructed safely. If a class has two or three required fields and nothing optional, a plain constructor is simpler — don't add a builder just for ceremony.
The interview-ready summary
"Builder constructs a complex object step by step with a fluent chain of methods and a final build(), instead of a giant telescoping constructor. Each method sets one field and returns the builder, so the call reads clearly and only sets what's needed — and the resulting object can be immutable, with validation in build(). It's the pattern behind StringBuilder and Lombok's @Builder. I use it whenever there are many optional fields." Clear problem, clear payoff."
What to read next
- Prototype Pattern — the last creational pattern (cloning objects)
- Factory Method Pattern — choosing which class to create
- All Design Patterns (hub)
- ← The complete System Design guide (hub)