I agree with your view that a Builder is really just a glorified constructor, and that the "builder pattern is just a way to build an object similar to what a constructor does".

However, here are a few of scenarios where the complexity of constructing an object makes the use of a Builder compelling.

Object's dependencies collected over period of time

In Java, StringBuilder is commonly used when building a string over a period of time, or rather, within a complex procedure. For instance, if a server is communicating with a client over a socket, and wants to append some client responses to the string, but not others, and perhaps remove certain responses that were previously appended,the StringBuilder class can be used to do so. At the end of the client/server session, the server can invoke StringBuilder#toString to get the built String.

Lots of parameters

If a constructor has dozens of parameters, it may make the code more readable or easy to maintain to use a builder.

E.g.

new Foo(1,2,3,4,5,6,7,8,9,10,11,12)

Vs.

Foo.newBuilder()
   .bar(1)
   .bar(2)
   .quux(3)
   ...
   .build()

Constructing object graphs

Similar to the "lots of parameters" scenario, I think that the scenario where a builder is most compelling is when constructing a complex object graph. The other answers in this question refer to the telescoping anti-pattern. This scenario (building a complex object graph) can lead to "telescoping", which the Builder helps resolve.

For instance, imagine you have an object-oriented pipeline interface, where a Pipeline depends on Sequence which depends on Stage. A PipelineBuilder would not only provide a nice wrapper around the constructor of Pipeline, but also around the constructors Sequence and Stage, allowing you to compose a complex Pipeline from a single Builder interface.

Instead of telescoping constructors like so:

new Pipeline(
    new Sequence(
        new Stage(
            new StageFunction() {
                public function execute() {...}
            }
        ),
        new Stage(
            new StageFunction() {
                public function execute() {...}
            }
        )
    )
)

A PipelineBuilder would allow you to "collapse" the telescope.

Pipeline.newBuilder()
    .sequence()
        .stage(new StageFunction () {
            public function execute() {...}
        })
        .stage(new StageFunction () {
           public function execute() {...}
        })
    .build()

(Even though I have used indentation in a way that is reflective of the telescoping constructors, this is merely cosmetic, as opposed to structural.)

Answer from maxenglander on Stack Overflow
Top answer
1 of 4
66

I agree with your view that a Builder is really just a glorified constructor, and that the "builder pattern is just a way to build an object similar to what a constructor does".

However, here are a few of scenarios where the complexity of constructing an object makes the use of a Builder compelling.

Object's dependencies collected over period of time

In Java, StringBuilder is commonly used when building a string over a period of time, or rather, within a complex procedure. For instance, if a server is communicating with a client over a socket, and wants to append some client responses to the string, but not others, and perhaps remove certain responses that were previously appended,the StringBuilder class can be used to do so. At the end of the client/server session, the server can invoke StringBuilder#toString to get the built String.

Lots of parameters

If a constructor has dozens of parameters, it may make the code more readable or easy to maintain to use a builder.

E.g.

new Foo(1,2,3,4,5,6,7,8,9,10,11,12)

Vs.

Foo.newBuilder()
   .bar(1)
   .bar(2)
   .quux(3)
   ...
   .build()

Constructing object graphs

Similar to the "lots of parameters" scenario, I think that the scenario where a builder is most compelling is when constructing a complex object graph. The other answers in this question refer to the telescoping anti-pattern. This scenario (building a complex object graph) can lead to "telescoping", which the Builder helps resolve.

For instance, imagine you have an object-oriented pipeline interface, where a Pipeline depends on Sequence which depends on Stage. A PipelineBuilder would not only provide a nice wrapper around the constructor of Pipeline, but also around the constructors Sequence and Stage, allowing you to compose a complex Pipeline from a single Builder interface.

Instead of telescoping constructors like so:

new Pipeline(
    new Sequence(
        new Stage(
            new StageFunction() {
                public function execute() {...}
            }
        ),
        new Stage(
            new StageFunction() {
                public function execute() {...}
            }
        )
    )
)

A PipelineBuilder would allow you to "collapse" the telescope.

Pipeline.newBuilder()
    .sequence()
        .stage(new StageFunction () {
            public function execute() {...}
        })
        .stage(new StageFunction () {
           public function execute() {...}
        })
    .build()

(Even though I have used indentation in a way that is reflective of the telescoping constructors, this is merely cosmetic, as opposed to structural.)

2 of 4
14

From the Wikipedia page:

The telescoping constructor anti-pattern occurs when the increase of object constructor parameter combination leads to an exponential list of constructors. Instead of using numerous constructors, the builder pattern uses another object, a builder, that receives each initialization parameter step by step and then returns the resulting constructed object at once

So if I have an object requiring many construction parameters, and those parameters are required in a variety of combinations (thus making some parameters optional) then a builder is a good approach.

e.g. I could create multiple different constructors for an object, or I could do the following:

new ObjectBuilder().withParam1(1).withParam4(4).withParam19(19).build();

thus allowing me to select the parameters required, and not have to define many different constructors. Note also that the above can allow you to populate a builder, and set parameters/call build() multiple times to create a set of related objects easily.

🌐
Reddit
reddit.com › r/programming › builder vs constructor : software engineer’s dilemma
r/programming on Reddit: Builder Vs Constructor : Software Engineer’s dilemma
December 25, 2024 - For builders there is the capability of having a mix of mandatory or optional param: the simple way is to have args in the builder constructor and then a more traditional builder pattern. A neater way is to use inner classes to limit what methods are available.
Discussions

Constructor with tons of parameters vs builder pattern - Software Engineering Stack Exchange
It is well know that if your class have a constructor with many parameters, say more than 4, then it is most probably a code smell. You need to reconsider if the class satisfies SRP. But what if we More on softwareengineering.stackexchange.com
🌐 softwareengineering.stackexchange.com
February 28, 2016
java - lombok @Builder vs constructor - Stack Overflow
@NguyễnVănPhong A programming ... way, but Java does not. 2021-08-09T13:30:16.933Z+00:00 ... Oh. I was so surprised. Let’s me check then get back to you soon if I have any question. +1 2021-08-09T13:39:01.153Z+00:00 ... This is not a lombok specific feature, this is called a builder pattern. Imagine you have a class with 20 parameters, and 10 of them are optional. You could somehow make tons of constructors taking care ... More on stackoverflow.com
🌐 stackoverflow.com
Is it better to use setters over constructors when a class have too many attributes?
No. Use a builder. Make sure your class has a single responsibility. More on reddit.com
🌐 r/javahelp
24
11
June 11, 2019
java - Builder with constructor or factory method? - Software Engineering Stack Exchange
Let's say I have a class Dot with a builder: public class Dot { private final Double x; private final Double y; private final Color color; private Dot(Double x, Double y, Color co... More on softwareengineering.stackexchange.com
🌐 softwareengineering.stackexchange.com
December 13, 2017
People also ask

What is the difference between a Builder and a constructor?
A constructor is a special method used to initialize a new instance of a class, primarily handling mandatory parameters. It ensures that an object starts in a valid state but can become unwieldy with multiple or optional parameters. In contrast, a builder is part of the builder pattern, providing a flexible and readable way to construct complex objects. Builders allow you to set optional parameters through builder methods, enhancing code maintainability and enabling the creation of multiple object configurations without the need for numerous constructors.
🌐
dhiwise.com
dhiwise.com › blog › design-converter › constructor-vs-builder-making-the-right-choice-for-your-project
Constructor vs. Builder: A Clear Comparison Guide
What does @builder do in Java?
In Java, the @Builder annotation is provided by libraries like Lombok to automatically generate a builder pattern implementation for a class. This builder facilitates the creation of complex objects by providing a fluent interface with builder methods for setting properties. Using @Builder simplifies the object construction process, reduces boilerplate code, and enhances readability and maintainability by allowing developers to create instances with optional parameters seamlessly.
🌐
dhiwise.com
dhiwise.com › blog › design-converter › constructor-vs-builder-making-the-right-choice-for-your-project
Constructor vs. Builder: A Clear Comparison Guide
What are the 3 types of constructor?
In Java, constructors can be categorized into three types: 1. Default Constructor: A no-argument constructor automatically provided by the compiler if no other constructors are defined. It initializes object fields with default values. 2. Parameterized Constructor: Accepts arguments to initialize an object with specific values, allowing for more controlled object creation. 3. Copy Constructor: Although not built into Java, it is a user-defined constructor that creates a new object by copying the fields of an existing instance, facilitating the duplication of objects. Each type serves diffe
🌐
dhiwise.com
dhiwise.com › blog › design-converter › constructor-vs-builder-making-the-right-choice-for-your-project
Constructor vs. Builder: A Clear Comparison Guide
🌐
DhiWise
dhiwise.com › blog › design-converter › constructor-vs-builder-making-the-right-choice-for-your-project
Constructor vs. Builder: A Clear Comparison Guide
January 7, 2025 - However, they can become cumbersome ... and understand. A builder is a design pattern that provides a flexible solution for creating objects with multiple parameters, especially when some parameters are optional....
Top answer
1 of 3
30

The Builder Pattern does not solve the “problem” of many arguments. But why are many arguments problematic?

  • They indicate your class might be doing too much. However, there are many types that legitimately contain many members that cannot be sensibly grouped.
  • Testing and understanding a function with many inputs gets exponentially more complicated – literally!
  • When the language does not offer named parameters, a function call is not self-documenting. Reading a function call with many arguments is quite difficult because you have no idea what the 7th parameter is supposed to do. You wouldn't even notice if the 5th and 6th argument were swapped accidentally, especially if you're in a dynamically typed language or everything happens to be a string, or when the last parameter is true for some reason.

Faking named parameters

The Builder Pattern addresses only one of these problems, namely the maintainability concerns of function calls with many arguments. So a function call like

MyClass o = new MyClass(a, b, c, d, e, f, g);

might become

MyClass o = MyClass.builder()
  .a(a).b(b).c(c).d(d).e(e).f(f).g(g)
  .build();

∗ The Builder pattern was originally intended as a representation-agnostic approach to assemble composite objects, which is a far greater aspiration than just named arguments for parameters. In particular, the builder pattern does not require a fluent interface.

This offers a bit of extra safety since it will blow up if you invoke a builder method that doesn't exist, but it otherwise does not bring you anything that a comment in the constructor call wouldn't have. Also, manually creating a builder requires code, and more code can always contain more bugs.

In languages where it is easy to define a new value type, I've found that it's way better to use microtyping/tiny types to simulate named arguments. It is named so because the types are really small, but you end up typing a lot more ;-)

MyClass o = new MyClass(
  new MyClass.A(a), new MyClass.B(b), new MyClass.C(c),
  new MyClass.D(d), new MyClass.E(e), new MyClass.F(f),
  new MyClass.G(g));

Obviously, the type names A, B, C, … should be self-documenting names that illustrate the meaning of the the parameter, often the same name as you'd give the parameter variable. Compared with the builder-for-named-arguments idiom, the required implementation is a lot simpler, and thus less likely to contain bugs. For example (with Java-ish syntax):

class MyClass {
  ...
  public static class A {
    public final int value;
    public A(int a) { value = a; }
  }
  ...
}

The compiler helps you guarantee that all arguments were provided; with a Builder you'd have to manually check for missing arguments, or encode a state machine into the host language type system – both would likely contain bugs.

There is another common approach to simulate named arguments: a single abstract parameter object that uses an inline class syntax to initialize all fields. In Java:

MyClass o = new MyClass(new MyClass.Arguments(){{ argA = a; argB = b; argC = c; ... }});

class MyClass {
  ...
  public static abstract class Arguments {
    public int argA;
    public String ArgB;
    ...
  }
}

However, it is possible to forget fields, and this is a quite language-specific solution (I've seen uses in JavaScript, C#, and C).

Fortunately, the constructor can still validate all arguments, which is not the case when your objects are created in a partially-constructed state, and require the user to provide further arguments via setters or an init() method – those require the least coding effort, but make it more difficult to write correct programs.

So while there are many approaches to address the “many unnamed parameters make code difficult to maintain problem”, other problems remain.

Approaching the root problem

For example the testability problem. When I write unit tests, I need the ability to inject test data, and to provide test implementations to mock out dependencies and operations that have external side effects. I can't do that when you instantiate any classes within your constructor. Unless the responsibility of your class is the creation of other objects, it shouldn't instantiate any non-trivial classes. This goes hand in hand with the single responsibility problem. The more focussed the responsibility of a class, the easier it is to test (and often easier to use).

The easiest and often best approach is for the constructor to take fully-constructed dependencies as parameter, though this shoves the responsibility of managing dependencies to the caller – not ideal either, unless the dependencies are independent entities in your domain model.

Sometimes (abstract) factories or full dependency injection frameworks are used instead, though these might be overkill in the majority of use cases. In particular, these only reduce the number of arguments if many of these arguments are quasi-global objects or configuration values that don't change between object instantiation. E.g. if parameters a and d were global-ish, we'd get

Dependencies deps = new Dependencies(a, d);
...
MyClass o = deps.newMyClass(b, c, e, f, g);

class MyClass {
  MyClass(Dependencies deps, B b, C c, E e, F f, G g) {
    this.depA = deps.newDepA(b, c);
    this.depB = deps.newDepB(e, f);
    this.g = g;
  }
  ...
}

class Dependencies {
  private A a;
  private D d;
  public Dependencies(A a, D d) { this.a = a; this.d = d; }
  public DepA newDepA(B b, C c) { return new DepA(a, b, c); }
  public DepB newDepB(E e, F f) { return new DepB(d, e, f); }
  public MyClass newMyClass(B b, C c, E e, F f, G g) {
    return new MyClass(deps, b, c, e, f, g);
  }
}

Depending on the application, this might be a game-changer where the factory methods end up having nearly no arguments because all can be provided by the dependency manager, or it might be a large amount of code that complicates instantiation for no apparent benefit. Such factories are way more useful for mapping interfaces to concrete types than they are for managing parameters. However, this approach tries to addresses the root problem of too many parameters rather than just hiding it with a pretty fluent interface.

2 of 3
10

Builder pattern does not solve anything for you and does not fix design failures.

If you have a class needing 10 parameters to be constructed, making a builder to construct it will not suddenly make your design better. You should opt for refactoring the class in question.

On the other hand, if you have a class, perhaps a simple DTO, where certain attributes of the class are optional, builder pattern could ease the construction of said object.

🌐
Medium
medium.com › @kariapratham › constructor-vs-static-factory-vs-builder-pattern-when-and-what-to-use-in-java-5f1ec79d3cc5
Constructor vs Static Factory vs Builder Pattern: When and What to Use in Java | by Pratham Karia | Medium
June 19, 2025 - The builder pattern offers the ... principle when designing immutable classes. Builders are slightly more verbose and require more boilerplate than constructors or factory methods....
Find elsewhere
🌐
Slideshare
slideshare.net › home › technology › builder pattern vs constructor
Builder pattern vs constructor | PPTX
February 7, 2017 - Constructors provide concise code ... code and memory usage. Builders let data be set one by one as it becomes available, such as from asynchronous calls, while constructors require all data at once....
🌐
Medium
medium.com › @ajinkyabadve › builder-design-patterns-in-java-1ffb12648850
Builder Design Patterns in Java. While Considering the builder pattern… | by Ajinkya Badve | Medium
October 24, 2018 - Builder pattern is used to create instance of very complex object having telescoping constructor in easiest way. Constructors in Java are used to create object and can take parameters required to create object.
🌐
DZone
dzone.com › coding › languages › the builder design pattern in java
The Builder Design Pattern in Java
October 22, 2018 - But, nothing is perfect; the Builder pattern has its own disadvantages, like being more verbose than the telescoping constructor pattern. Keep in mind that if your class has multiple attributes with the same type or optional when you design your class, it is time to consider the Builder Pattern. If now, you may want to add more parameters to your class, then it is never too late to consider refactoring your code with the Builder pattern. To wrap up this post, I would like to cite some words from Joshua Bloch's Effective Java:
🌐
Medium
medium.com › javarevisited › when-constructors-arent-doing-it-for-you-use-a-builder-11559fa41e39
How the builder design pattern works in Java | Javarevisited
September 28, 2021 - IncomeTaxReturn.java using the builder pattern. ... The tax return has only final fields where the optional values have been specified in the builder. It is very easy to create any type of combination of complicated tax returns. We can also add new fields without breaking current users. The tax return cannot be created without using a builder due to having a private constructor.
🌐
Medium
serpro69.medium.com › the-builder-pattern-in-java-2c03fc6ccd16
The Builder pattern in Java — yet another Builder Pattern article? | by Serhii Prodan | Medium
April 1, 2019 - Overall, the Builder pattern is a very commonly used technique for creating objects and is a good choice to use when classes have constructors with multiple parameters (especially optional ones) and are likely to change in the future. The code becomes much easier to write and read as compared to overridden constructors, and the class scales just as well as JavaBeans but is much safer.
🌐
HowToDoInJava
howtodoinjava.com › home › design patterns › creational › java builder pattern: build complex objects efficiently
Java Builder Pattern: Build Complex Objects Efficiently
October 14, 2023 - I will suggest to create a constructor with all mandatory fields as arguments. This way you can force the coder to pass all mandatory fields even before getting the builder object. This will also remove unnecessary checks for mandatory fields inside build() method. You can remove the setter methods for these mandatory fields to avoid overriding them wrongly. Note: Keep the number of mandatory fields to minimum. Reply · “java.lang.Appendable are in fact good example of use of Builder pattern” ???
🌐
YouTube
youtube.com › watch
The Builder Pattern vs. Constructor #java #shorts
Enjoy the videos and music you love, upload original content, and share it all with friends, family, and the world on YouTube.
Top answer
1 of 1
2

Builder is a class internal to Dot. For me this tells me that Builder is strongly coupled with Dot and that Builder is a utility of Dot for some objective, in this case object construction.

This is objectively one step away from Builder being an internal class hidden away from the caller entirely. The only link you, the caller, should have to Builder should be through Dot as a general rule. And although there's nothing stopping you from making Builder's constructor public and accessing it directly, I confirmly believe it is an antipattern.

Therefore, you should have a static factory method in Dot that returns an instance of Builder. You mention that it isn't likely that you'd ever need to extend Builder, and that's all fine and good, but when you're given a more flexible option with no drawbacks while you're developing, you grab hold of it like your life depended on it. Should you ever need to extend Builder, you could make Builder<T> an interface and create a customized DotBuilder<Dot> which implements it which when called creates an instance of Dot.

My best argument for using a factory method would be: Say that the builder uses a final field String id that has to be set in its constructor, but certain restrictions apply to what constitutes an ID. Throwing an exception on an illegal id string should not be done in a constructor. Therefore a factory method would be better.

I'm usually against constructors performing work that might likely throw exceptions. It's one thing to throw an exception in a constructor for an invalid parameter or for a very unlikely situation such as Xml implementation not existing, and quite another to attempt to establish a database connection which can and will fail quite easily. If you did need to do work in your Builder constructor, you could do so lazily putting it off until the actual creation of the object as to not make your constructor explode. Though if I've got Builder class pegged correctly, it isn't the type of class that should ever explode upon creation. If that isn't your case, give serious thought to making it work in the way that one might expect it to work (aka possible exceptions when calling build() method only).

Also if I may add, having a builder class Builder with many of the same methods as Dot is not probably a good idea. Your situation may be different and this may be the simplified version, so if this doesn't apply to you, ignore this advice. Though it is my opinion that Builder is largely unnecessary here. Dot can return this after each setter and perform precisely the same functionality. Give it some thought.

🌐
Stack Abuse
stackabuse.com › the-builder-design-pattern-in-java
The Builder Design Pattern in Java
February 13, 2023 - The Builder Pattern separates the construction from the representation. ... The construction is done in the class itself. The representation is what we see as the user of the class. Right now, both of our classes above have these two tied together - we directly call the constructor with the ...
🌐
DigitalOcean
digitalocean.com › community › tutorials › builder-design-pattern-in-java
Builder Design Pattern in Java: Guide & Examples | DigitalOcean
August 3, 2022 - We can solve the issues with large number of parameters by providing a constructor with required parameters and then different setter methods to set the optional parameters. The problem with this approach is that the Object state will be inconsistent until unless all the attributes are set explicitly. Builder pattern solves the issue with large number of optional parameters and inconsistent state by providing a way to build the object step-by-step and provide a method that will actually return the final Object.
🌐
Petri Kainulainen
petrikainulainen.net › home › blog › three reasons why i like the builder pattern
Three Reasons Why I Like the Builder Pattern - Petri Kainulainen
July 13, 2016 - There are three ways to create new objects in Java programming language: The telescoping constructor (anti)pattern The Javabeans pattern The builder pattern I prefer the builder pattern over the other two methods. Why? Joshua Bloch described the builder pattern and the benefits of using it in Effective Java.
🌐
Project Lombok
projectlombok.org › features › Builder
@Builder
Now that the "method" mode is clear, putting a @Builder annotation on a constructor functions similarly; effectively, constructors are just static methods that have a special syntax to invoke them: Their 'return type' is the class they construct, and their type parameters are the same as the type parameters of the class itself.
🌐
Quora
quora.com › Why-do-we-use-a-builder-pattern-in-Java-when-we-can-just-create-a-no-args-constructor-and-other-setter-methods-for-each-field-in-it
Why do we use a builder pattern in Java when we can just create a no-args constructor and other setter methods for each field in it? - Quora
Answer (1 of 6): The reason is because the needs of instantiating an object (especially during testing) mean you’ll have a lot of New’s everywhere that you might have to find and replace. The obvious solution is a factory. But then that has limitations, you might end up working with very ...