Builder vs telescoping constructors
Fast recall
Quick revision
Core answer
Interview-ready guide
Interview answer
A telescoping constructor has several overloads, normally adding optional parameters step by step and delegating to a full constructor. Its main problem is readability and flexibility, not an automatic exponential number of overloads. For example, new User("Asha", true, false, null) does not show which boolean or missing string represents which option, while User.builder("Asha").marketingOptIn(true).build() names the choice. A builder also lets optional values appear in a clearer order and supports combination checks at build(). That benefit costs extra API surface and a temporary mutable builder. For a small object with a few obvious required values, I would keep a constructor or record.
Builder vs telescoping constructors
Direct Answer
A telescoping constructor API adds overloads as optional parameters are introduced, often forwarding shorter overloads to one full constructor. It becomes hard to read because call sites contain several same-typed positional values and adding an option changes signatures. The number of overloads is not inherently exponential unless the API tries to support every combination. A builder trades extra code and allocation for named, flexible construction.
Code Example
// TELESCOPING CONSTRUCTORS: overloads explode with each optional field
class UserBad {
UserBad(String id, String email) { this(id, email, null); }
UserBad(String id, String email, String phone) { this(id, email, phone, null); }
UserBad(String id, String email, String phone, String bio) { /* ... */ }
// 4 optionals -> up to 16 overloads; positional args are easy to swap by mistake
}
// BUILDER: one fluent path, named setters, scales linearly
class User {
private final String id, email, phone, bio;
private User(Builder b){ id = b.id; email = b.email; phone = b.phone; bio = b.bio; }
static class Builder {
private final String id, email; // required
private String phone, bio; // optional
Builder(String id, String email){ this.id = id; this.email = email; }
Builder phone(String p){ this.phone = p; return this; }
Builder bio(String b){ this.bio = b; return this; }
User build(){ return new User(this); }
}
}
// Usage: new User.Builder("u1", "a@b.com").phone("99999").build();
Common Mistakes & Pitfalls
- Claiming exponential overloads are inevitable: a normal telescoping chain is often linear; unreadable positions are still a real problem.
- Switching by a fixed parameter count: clarity and invariants matter more than one threshold.
- Dropping constructor validation: a builder still needs to protect the final object's rules.
- Using Builder for every value: a record or constructor may be smaller and clearer.
- Keeping unrelated construction paths: define which APIs are supported so rules do not drift.
Check your understanding
Answer these without looking back at the article.
- At what point should you switch from constructor parameters to a Builder?
- Does Builder pattern have any downsides compared to constructors?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.