What is builder() in Java?

Rita 52 Published: 09/19/2024

What is builder() in Java?

The builder() pattern in Java is a creational design pattern that allows for the construction of complex objects step-by-step. It provides a way to separate the construction of an object from its representation, which makes it easier to create and use complex objects.

In traditional object-oriented programming, constructors are often used to initialize objects with required values. However, in cases where there are many attributes or when the number of arguments is large, the constructor can become quite verbose and difficult to read. This is where the builder() pattern comes into play.

The builder() pattern creates a separate class that is responsible for constructing an object. This class is often referred to as the "builder" class. The builder class provides methods that allow you to set the values of an object's attributes, one at a time. Each method returns the builder instance itself, allowing the calls to be chained together.

For example, let's say we want to create a Person class with name, age, and address attributes. Using the traditional constructor approach, the code might look like this:

public Person(String name, int age, String address) {

this.name = name;

this.age = age;

this.address = address;

}

However, if we add more attributes or methods, the constructor can become quite long and unwieldy. That's where the builder() pattern comes in:

public class Person {

private String name;

private int age;

private Address address;

public static class Builder {

private String name;

private int age;

private Address address;

public Builder(String name) {

this.name = name;

}

public Builder withAge(int age) {

this.age = age;

return this;

}

public Builder withAddress(Address address) {

this.address = address;

return this;

}

public Person build() {

return new Person(this);

}

}

private Person(Builder builder) {

this.name = builder.name;

this.age = builder.age;

this.address = builder.address;

}

}

In this example, we create a Person class with a static nested Builder class. The Builder class provides methods to set the values of the attributes, one at a time. Each method returns itself, allowing the calls to be chained together.

To use the builder() pattern, you would typically do something like this:

Person person = new Person.Builder("John")

.withAge(30)

.withAddress(new Address("123 Main St"))

.build();

This approach can greatly improve the readability and maintainability of your code. It also provides a way to validate or transform the input values before the object is created.

In conclusion, the builder() pattern in Java is a powerful tool that allows for the construction of complex objects step-by-step. It provides a way to separate the construction of an object from its representation, making it easier to create and use complex objects.

Java builder annotation example

Here's an example of using the Java Builder annotation:

The Java Builder pattern is a creational design pattern that allows you to construct complex objects step-by-step, separating the construction process from its representation.

Let's consider a simple example of building a car. The car has several attributes like color, model, and speed. You can use the Builder pattern to create a Car class with a Builder interface:

public abstract class CarBuilder {

protected String color;

protected String model;

public abstract CarBuilder setColor(String color);

public abstract CarBuilder setModel(String model);

public Car build() {

return new Car(color, model);

}

}

public class Car {

private final String color;

private final String model;

public Car(String color, String model) {

this.color = color;

this.model = model;

}

@Override

public String toString() {

return "Car{" +

"color='" + color + ''' +

", model='" + model + ''' +

'}';

}

}

public class SedanBuilder extends CarBuilder {

private String speed;

@Override

public SedanBuilder setColor(String color) {

this.color = color;

return this;

}

@Override

public SedanBuilder setModel(String model) {

this.model = model;

return this;

}

@Override

public SedanBuilder setSpeed(String speed) {

this.speed = speed;

return this;

}

public Car build() {

return new Car(color, model);

}

}

public class SUVBuilder extends CarBuilder {

private String topSpeed;

@Override

public SUVBuilder setColor(String color) {

this.color = color;

return this;

}

@Override

public SUVBuilder setModel(String model) {

this.model = model;

return this;

}

@Override

public SUVBuilder setTopSpeed(String topSpeed) {

this.topSpeed = topSpeed;

return this;

}

public Car build() {

return new Car(color, model);

}

}

public class Main {

public static void main(String[] args) {

SedanBuilder sedans = new SedanBuilder()

.setColor("Red")

.setModel("Toyota Corolla")

.setSpeed("120mph");

SUVBuilder suvs = new SUVBuilder()

.setColor("Black")

.setModel("Ford Explorer")

.setTopSpeed("150mph");

Car car1 = sedans.build();

Car car2 = suvs.build();

System.out.println(car1.toString());

System.out.println(car2.toString());

}

}

In the above code, you can see that there are three classes: Car, CarBuilder, and two specific builders (SedanBuilder and SUVBuilder). Each of these builders has methods for setting attributes (color, model, speed, topSpeed), which return a reference to itself. This is known as the "fluent interface" or "method chaining".

When you want to build a car, you create an instance of one of the specific builders and set the desired attributes using its setter methods. Once the attributes are set, you call the build method on the builder to get the constructed car.

This design pattern allows for greater flexibility in building objects, as it decouples the construction process from its representation. It also makes your code more readable, as you can chain together multiple setter calls without having to create intermediate objects.

In this example, we've used the Builder pattern with a simple Car class. However, you could apply it to much more complex classes and scenarios, such as building XML or JSON structures, configuring database queries, etc.