Full Stack • Java • System Design • Cloud • AI Engineering

Builder Design Pattern in Java

Learn Builder Design Pattern in Java with diagrams, real-world examples, fluent APIs, Lombok @Builder, Spring Boot examples, input/output, benefits, limitations, and interview questions.

Introduction

One of the most common problems in Java applications is creating objects with many optional parameters.

Imagine creating a Customer object:

Customer
├── firstName
├── lastName
├── email
├── phone
├── address
├── city
├── state
├── zipCode
├── country
└── age

Using constructors becomes difficult and confusing.

This problem is solved using:

Builder Design Pattern


Purpose of Builder Pattern

The main purpose of Builder Pattern is:

Create complex objects step-by-step while keeping object creation readable and maintainable.

Builder separates:

Object Construction
        From
Object Representation

Real World Analogy

Imagine ordering a burger.

You choose:

Bread
Patty
Cheese
Sauce
Vegetables

The kitchen assembles the burger step by step.

You don't need multiple burger constructors.

This is exactly how Builder works.


Problem Without Builder

Suppose we have a Customer class.

public class Customer {

    private String firstName;
    private String lastName;
    private String email;
    private String phone;
    private String city;
    private String country;

    public Customer(
            String firstName,
            String lastName,
            String email,
            String phone,
            String city,
            String country) {

        this.firstName = firstName;
        this.lastName = lastName;
        this.email = email;
        this.phone = phone;
        this.city = city;
        this.country = country;
    }
}

Client Code

Customer customer =
    new Customer(
        "Venu",
        "Reddy",
        "[email protected]",
        "1234567890",
        "San Antonio",
        "USA");

Problem:

What is parameter #4?
What is parameter #5?

Hard to read.


Telescoping Constructor Problem

As fields increase:

Customer()
Customer(String firstName)
Customer(String firstName, String lastName)
Customer(String firstName, String lastName, String email)
Customer(String firstName, String lastName, String email, String phone)
...

The number of constructors grows rapidly.


Builder Pattern Solution

Builder Pattern solves the problem by creating the object step by step using readable method names.

flowchart LR
    A[Builder Object] --> B[Set First Name]
    B --> C[Set Last Name]
    C --> D[Set Email]
    D --> E[Set Phone]
    E --> F[Call build Method]
    F --> G[Customer Object Created]

Builder Pattern Structure

classDiagram

class Customer {
    -firstName
    -lastName
    -email
    -phone
}

class CustomerBuilder {
    +firstName()
    +lastName()
    +email()
    +phone()
    +build()
}

CustomerBuilder --> Customer

Builder Implementation

Customer Class

public class Customer {

    private String firstName;
    private String lastName;
    private String email;
    private String phone;
    private String city;

    private Customer(CustomerBuilder builder) {

        this.firstName = builder.firstName;
        this.lastName = builder.lastName;
        this.email = builder.email;
        this.phone = builder.phone;
        this.city = builder.city;
    }

    public static class CustomerBuilder {

        private String firstName;
        private String lastName;
        private String email;
        private String phone;
        private String city;

        public CustomerBuilder firstName(String firstName) {
            this.firstName = firstName;
            return this;
        }

        public CustomerBuilder lastName(String lastName) {
            this.lastName = lastName;
            return this;
        }

        public CustomerBuilder email(String email) {
            this.email = email;
            return this;
        }

        public CustomerBuilder phone(String phone) {
            this.phone = phone;
            return this;
        }

        public CustomerBuilder city(String city) {
            this.city = city;
            return this;
        }

        public Customer build() {
            return new Customer(this);
        }
    }
}

Client Code

Customer customer =
    new Customer.CustomerBuilder()
        .firstName("Venu")
        .lastName("Reddy")
        .email("[email protected]")
        .phone("1234567890")
        .city("San Antonio")
        .build();

Output

Customer Created Successfully

Why This Is Better?

Instead of:

new Customer(
 "Venu",
 "Reddy",
 "[email protected]",
 "1234567890",
 "San Antonio"
);

We get:

new Customer.CustomerBuilder()
    .firstName("Venu")
    .lastName("Reddy")
    .city("San Antonio")
    .build();

Much easier to read.


Object Creation Flow

sequenceDiagram

participant Client
participant Builder
participant Customer

Client->>Builder:firstName()
Client->>Builder:lastName()
Client->>Builder:email()

Client->>Builder:build()

Builder->>Customer:new Customer()

Customer-->>Client:Object Returned

Banking Example

Creating Loan Application.

Fields:

Applicant Name
Income
Credit Score
Loan Amount
Term
Collateral

Builder allows flexible object creation.


Loan Application Builder

LoanApplication application =
    new LoanApplication.Builder()
        .applicantName("Venu")
        .income(120000)
        .creditScore(800)
        .loanAmount(500000)
        .build();

Insurance Example

Creating Insurance Policy.

InsurancePolicy policy =
    new InsurancePolicy.Builder()
        .policyHolder("John")
        .sumInsured(1000000)
        .premium(5000)
        .build();

Microservices Example

Creating Kafka Events.

Without Builder:

new CustomerCreatedEvent(
    customerId,
    firstName,
    lastName,
    email,
    phone,
    address
);

With Builder:

CustomerCreatedEvent event =
    CustomerCreatedEvent.builder()
        .customerId("1001")
        .firstName("Venu")
        .email("[email protected]")
        .build();

Much cleaner.


Builder in Kafka Event Architecture

flowchart LR

A[Order Service]

A --> B[Event Builder]

B --> C[Kafka Event]

C --> D[Kafka Topic]

Spring Boot Example

DTO Creation

public class EmployeeDTO {

    private String id;
    private String name;
    private String department;

    private EmployeeDTO(Builder builder) {
        this.id = builder.id;
        this.name = builder.name;
        this.department = builder.department;
    }
}

Builder makes DTO creation readable.


Most Popular Builder in Modern Java

Lombok Builder


Lombok Example

import lombok.Builder;
import lombok.Data;

@Data
@Builder
public class Employee {

    private String id;
    private String name;
    private String department;
    private String email;
}

Client Code

Employee employee =
    Employee.builder()
        .id("100")
        .name("Venu")
        .department("Engineering")
        .email("[email protected]")
        .build();

Output

Employee(id=100,
name=Venu,
department=Engineering,
[email protected])

Why Lombok Builder Is Popular?

Advantages:

Less Boilerplate
Readable Code
Immutable Support
Easy Maintenance

Builder Pattern in Frameworks

Common Framework Usage:

Framework Usage
Spring Boot ResponseEntity Builder
Lombok @Builder
Kafka ProducerRecord Builder Style
JPA Entity Construction
AWS SDK Request Builders
Google Cloud SDK Request Builders

Spring Framework Example

ResponseEntity
    .ok()
    .header("version", "1")
    .body(employee);

This follows Builder style.


AWS SDK Example

PutObjectRequest request =
    PutObjectRequest.builder()
        .bucket("documents")
        .key("report.pdf")
        .build();

Builder pattern is heavily used.


Benefits

✅ Readable Code

✅ Handles Many Optional Fields

✅ Avoids Constructor Explosion

✅ Supports Immutable Objects

✅ Easy To Maintain

✅ Easy To Extend

✅ Better API Design


Limitations

❌ More Classes

❌ Slightly More Code

❌ Overkill For Small Objects


When To Use

Use Builder when:

  • Object has many fields
  • Many optional parameters exist
  • Constructors become confusing
  • Immutable objects are required

Examples:

  • DTOs
  • Events
  • API Requests
  • Configuration Objects
  • Domain Models

When Not To Use

Avoid Builder when:

  • Object has only 2-3 fields
  • Construction logic is simple
  • Extra abstraction is unnecessary

Builder vs Factory Method

Feature Builder Factory Method
Purpose Build Complex Object Create Object
Multiple Steps Yes No
Optional Fields Excellent Limited
Fluent API Yes No
Object Families No No

Builder vs Abstract Factory

Feature Builder Abstract Factory
Creates Single Complex Object Family Of Objects
Focus Construction Process Product Families
Use Case DTO/Event Creation UI Components

Interview Questions

What problem does Builder solve?

It solves the telescoping constructor problem and improves readability.


Why is Builder better than constructors?

Named methods make code easier to understand.


What is Fluent API?

Returning this from methods to allow chaining.

Example:

builder
    .name("Venu")
    .email("[email protected]")
    .build();

Is Lombok Builder a Builder Pattern?

Yes.

@Builder automatically generates Builder code.


Where is Builder commonly used?

  • Spring Boot
  • AWS SDK
  • Kafka Events
  • DTOs
  • REST Requests

Key Takeaways

  • Builder is a Creational Design Pattern.
  • It creates complex objects step-by-step.
  • It solves constructor explosion problems.
  • Fluent APIs improve readability.
  • Lombok makes Builder implementation simple.
  • Widely used in Spring Boot, Kafka, AWS SDK, and enterprise applications.