NailYourInterview
Creational Design Patterns

Builder Design Pattern in Java with Example Explained

Learn the Builder Design Pattern in Java with example. Solve problems like constructor explosion and see how it helps create clean, maintainable code.

Builder Design Pattern

Video thumbnail

The Builder Design Pattern is a creational pattern used when you want to create complex or immutable objects step by step.

A Simple Real-Life Example

Builder Design Pattern Example
Builder Design Pattern Example

Imagine you're sending an email to a friend.

You add their email address, write the subject, and the body of the message. Finally, you click Send.

At that moment, an Email object is created.

Now think about this: what if someone could change your email after it was sent? 😬 Maybe they edit the message body or change the subject. That would be a serious problem, right?

That’s why, in such cases, we want to make the object immutable — meaning once it’s created, it can’t be changed.

Problem with Regular Approach (Without Builder)

Let’s first try to write this Email class without using the builder pattern:

Email.java
@Getter
public class Email {
    private String to;
    private String subject;
    private String body;
    private String cc;
    private String bcc;
    private List<String> attachments;
 
    public Email(String to, String subject, String body, String cc, String bcc, List<String> attachments) {
        this.to = to;
        this.subject = subject;
        this.body = body;
        this.cc = cc;
        this.bcc = bcc;
        this.attachments = attachments;
    }
 
    // Getters only – no setters (immutability)
}

Here, we’re using only getters and no setters, so no one can modify the email once it’s created. This makes the class immutable. So far so good.

But there's a big issue...

Common Problems Without Builder

Passing null values

What if you don’t want to set cc, bcc, or attachments?

Then you’ll end up doing this:

Email email = new Email(
    "[email protected]",
    "Request for course On SpringBoot",
    "Hi Shubh, ......",
    NULL,
    NULL,
    NULL
);

Now imagine your class has 30 attributes, but you only want to set 5. That means you’ll have to pass 25 null values — which is messy and confusing.

Constructor Overload (Too Many Constructors)

To avoid passing null, some developers create multiple constructors:

public class Email {
 
    // some might prefer just subject and body
    public Email(String to, String subject, String body) {
        //...
    }
 
    // some might prefer subject, body and cc
    public Student(String to, String subject, String body, String cc) {
        //...
    }
 
    // some might prefer subject, body, cc and attachments
    public Student(String to, String subject, String body, String cc, List<String> attachments) {
        //...
    }
 
    // some might prefer subject, body, attachments but not cc
    public Student(String to, String subject, String body, List<String> attachments) {
        //...
    }
 
    // some might use all
    public Student(String to, String subject, String body, String cc, String bcc, List<String> attachments) {
        //...
    }
 
    //... more permutations and combinations
}

This leads to Constructor Explosion — creating many constructors just to handle different combinations of fields. The number of constructors grows very fast when you add more fields.

The Better Way: Use Builder Design Pattern

The Builder pattern solves all these problems:

  • No more nulls
  • No constructor explosion
  • Easy to read
  • Still keeps your object immutable

UML

The simplified UML diagram for our requirement would be like this:

Builder Design Pattern UML
UML for Builder Design Pattern

You may have seen a Builder interface or Director class in some diagrams (like this one), but in this example, we don’t need them. The client (your code) directly uses the builder.

Ever used StringBuilder in Java? That’s actually a real-world example of this pattern! It is a builder for creating immutable String object.

Let’s Code with Builder Pattern

Here's how builder can help us overcome those problems.

@Getter
public class Email {
    private String to;
    private String subject;
    private String body;
    private String cc;
    private String bcc;
    private List<String> attachments;
 
    // We let the builder initialize the Email Object.
    Email(EmailBuilder builder){ 
        this.to = builder.getTo(); 
        this.subject = builder.getSubject(); 
        this.body = builder.getBody(); 
        this.cc = builder.getCc(); 
        this.bcc = builder.getBcc(); 
        this.attachments = builder.getAttachments(); 
    } 
 
    // Getters only – no setters (immutability)
}

Our goal is to create immutable Email class so even if EmailBuilder has setters, we dont mind. Checkout the build() function. This build() function is responsible to create the immutable Email object. So only way to create Email is to first create Builder and set all the required attributes and at last call the build() method which takes in the builder object as parameter.

Main.java
public class Main {
    public static void main(String[] args) {
        EmailBuilder builder = new EmailBuilder();
        Email email = builder
                            .setTo("[email protected]")
                            .setSubject("Request for Java Multithreading Content")
                            .setBody("Hi Shubh, ....")
                            .build();
 
        // email is immutable because it does not have setters and the attributes are private.
        System.out.println(email);
    }
}

Now, we’ve created an immutable email object without writing multiple constructors or passing nulls.

Notice that we have used method chaining to create the object step by step which also results into clean code.

Key Benefits of Using the Builder Design Pattern