Builder pattern is a creational design pattern that builds a complex object step by step.
It separates the construction of a complex object from its representation, so that the same construction process can create different representations.
Confusing right ??
Let’s understand this with the help on an example.
Suppose you have an object to create a user profile which contains user’s first name and last name.
You can easily achieve the same as shown below.
class UserProfile {
private String firstName;
private String lastName;
public UserProfile(String firstName, String lastName){
this.firstName = firstName;
this.lastName = lastName;
}
}
class CreateUserProfiles {
public static void main(String[] args) {
UserProfile userProfile = new UserProfile("Java", "Guy");
}
}So far so good …
But now your clients want to have all the below as fields for your user profile.
- firstName
- lastName
- phone
- address
- preferences
- settings
- newsletter subscription
with firstName and lastName as mandatory filelds and remaining as optional fields.
Now one way to achieve this is:
class UserProfile {
// Mandatory
private String firstName;
private String lastName;
// Optional
private String email;
private String phone;
private String address;
private List<String> preferences;
private List<String> settings;
private boolean requireNewsletter;
public UserProfile( String firstName, String lastName,
String email, String phone, String address,
List<String> preferences, List<String> settings,
boolean requireNewsletter ) {
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
this.phone = phone;
this.address = address;
this.preferences = preferences;
this.settings = settings;
this.requireNewsletter = requireNewsletter;
}
}
class CreateUserProfiles {
public static void main(String[] args) {
UserProfile userProfile = new UserProfile("Java", "Guy", null, null, null, null, null, false);
}
}By now, you would have understood how inconvenient it is for the CreateUserProfiles class to create a user profile with all the forceful nulls in the object creation.
But what can we instead 🤔.
Let’s define a separate constructor for each of the optional fields.
class UserProfile {
// Mandatory
private String firstName;
private String lastName;
// Optional
private String email;
private String phone;
private String address;
private List<String> preferences;
private List<String> settings;
private boolean requireNewsletter;
// Constructor 1: Only mandatory
public UserProfile(String firstName, String lastName) {
this(firstName, lastName, null);
}
// Constructor 2: + email
public UserProfile(String firstName, String lastName, String email) {
this(firstName, lastName, email, null);
}
// Constructor 3: + phone
public UserProfile(String firstName, String lastName, String email, String phone) {
this(firstName, lastName, email, phone, null);
}
// Constructor 4: + address
public UserProfile(String firstName, String lastName, String email,
String phone, String address) {
this(firstName, lastName, email, phone, address, null);
}
// Constructor 5: + preferences
public UserProfile(String firstName, String lastName, String email,
String phone, String address,
List<String> preferences) {
this(firstName, lastName, email, phone, address, preferences, null);
}
// Constructor 6: + settings
public UserProfile(String firstName, String lastName, String email,
String phone, String address,
List<String> preferences, List<String> settings) {
this(firstName, lastName, email, phone, address, preferences, settings, false);
}
// Constructor 7: Full version
public UserProfile(String firstName, String lastName, String email,
String phone, String address,
List<String> preferences, List<String> settings,
boolean requireNewsletter) {
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
this.phone = phone;
this.address = address;
this.preferences = preferences;
this.settings = settings;
this.requireNewsletter = requireNewsletter;
}
}
Do you start to notice a problem ??
This is known as the Telescoping Constructor Anti-Pattern. It results in a chain of constructors that:
- Are hard to read and write
- Become error-prone because the parameter order is easy to mix up
- Are difficult to maintain as more fields are added
- Are inflexible, forcing users to supply arguments in a strict sequence
Now just imagine that your clients want you to add 20 new optional fields in the user profile class 🤯.

It’s alright… don’t panic… stay cool, and breathe …
Builder Pattern to the rescue …
To fix the constructor issues we saw earlier, we use the Builder Pattern. It separates how an object is built from what it represents, letting us create it step-by-step while keeping the result clean, readable, and immutable.
class UserProfile {
// Mandatory
private final String firstName;
private final String lastName;
// Optional
private final String email;
private final String phone;
private final String address;
private final List<String> preferences;
private final List<String> settings;
private final boolean requireNewsletter;
private UserProfile( UserProfileBuilder builder ){
this.firstName = builder.firstName;
this.lastName = builder.lastName;
this.email = builder.email;
this.phone = builder.phone;
this.address = builder.address;
this.preferences = builder.preferences;
this.settings = builder.settings;
this.requireNewsletter = builder.requireNewsletter;
}
public static class UserProfileBuilder {
// Mandatory
private final String firstName;
private final String lastName;
// Optional
private String email;
private String phone;
private String address;
private List<String> preferences;
private List<String> settings;
private boolean requireNewsletter;
public UserProfileBuilder(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public UserProfileBuilder withEmail(String email) {
this.email = email;
return this;
}
public UserProfileBuilder withPhone( String phone ) {
this.phone = phone;
return this;
}
public UserProfileBuilder withAddress( String address ) {
this.address = address;
return this;
}
public UserProfileBuilder withPreferences( List<String> preferences ) {
this.preferences = preferences;
return this;
}
public UserProfileBuilder withSettings( List<String> settings ) {
this.settings = settings;
return this;
}
public UserProfileBuilder withRequireNewsletter( boolean requireNewsletter ) {
this.requireNewsletter = requireNewsletter;
return this;
}
public UserProfile build() {
return new UserProfile(this);
}
}
}Now let’s understand what we did in the above code:
- The
UserProfileconstructor is private, so objects can only be created through the builder. - This builder class contains the same fields as
UserProfile(with the slight exception that here the optional fields are not marked final), maintaining immutability and controlling object creation. - Each method (like
withEmail,withPhone) returns the builder itself, allowing readable method chaining. - Mandatory fields (
firstName,lastName) are passed to the builder’s constructor, while all other fields are optional and set viawithFieldName()methods. - After setting all desired fields, calling
.build()completes object creation and returns the fully constructedUserProfileinstance.
OK… But how do we now create UserProfile objects using this builder design pattern??
That’s the easy part…
class CreateUserProfiles {
public static void main(String[] args) {
UserProfile userProfile = new UserProfile.UserProfileBuilder("Java", "Guy")
.withEmail("justanotherjavaguy@gmail.com") // optional
.withRequireNewsletter(true) // optional
.build();
}
}- Mandatory fields (
firstName,lastName) are passed to the builder constructor. - Optional fields are set fluently using
withEmail()andwithRequireNewsletter(). .build()finalizes the object and returns an immutableUserProfileinstance.
If you’re using Spring Boot or similar frameworks, you can leverage Lombok’s @Builder annotation to generate a builder automatically, instead of writing the builder class from scratch like this:
@Builder
class UserProfile {
private String firstName;
private String lastName;
private String email;
private String phone;
private String address;
private List<String> preferences;
private List<String> settings;
private boolean requireNewsletter;
}And with that, we’ve wrapped up the Builder Design Pattern — you’re now fully equipped with everything you need to know on Builder 🥳.