Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Java Builders From The Start

DZone's Guide to

Java Builders From The Start

The builder pattern is an often used and often abused pattern. In this article we discuss the when, why and how of this Java staple.

· Java Zone
Free Resource

The single app analytics solutions to take your web and mobile apps to the next level.  Try today!  Brought to you in partnership with CA Technologies

Builders are on of the patterns I see most misused in a code base. Hopefully this article will help you to correctly kow when and how to use them.

Builders are best used as a cure for overly long constructors.

public MegaConstructor(
    String something,
    String somethingElse,
    String aConnection,
    int aPort,
    ExpensiveObject anotherObject,
    ExpensiveObject moreObjects,
    String blah,
    double huh
){

}

You’ve all seen this code. The worst thing is this sort of constructor tends to get abused even further, with multiple overridden constructors making it near impossible to figure out what’s going on. When you’re creating the object you keep having to flick back and forth to figure out what parameter is next. Refactoring is a nightmare.

Java forces constructor ordering of parameters and it is not clear from them what each one is for. How many times have you seen this in a test set up class

new MegaConstructor(null, null, null, 0, null, null, null, 0.0);


Yikes. Or worse:

new MegaConstructor(null, "The bit I’m testing", null, 0, null, null, null, 0.0);

Generally, if your constructor is getting to 4 or more parameters, you want to start lookig at it’s legebility and whether it’s time to move over to a builder.

What is a builder then?

It’s the classic GoF pattern, that results in some code looking like this:

        new MegaConstructorBuilder()
        .something("mySomething")
        .somethingElse("mySomethingElse")
        .aConnection("Http://samatkinson.com")
        .aPort(1234)
        .expensiveObject(new ExpensiveObject())
        .moreObjects(new ExpensiveObject())
        .blah("rah!")
        .huh(1.4)
        .build();


The beauty of the builder is that it’s clear what each field being set is, and you can set them in any order that you wish.

The downside is that it’s still a very verbose set of code. In reality if you’re seeing code like this at least try to build the parameters up into bigger objects that you can play around with. This isn’t always possible, but should be worth a look. For example in the above, the aConnection/aPort probably live together in some sort of connection details object. You can often cut down on the size of your parameter list this way.

But let’s assume you can’t and you have to do a big builder. How should you implement it?

Immutable builders

The normal code that you will see for a builder is like this:

 private static class MegaConstructorBuilder {
    private String mySomething;
    private String mySomethingElse;
    private String connection;
    private int port;
    private ExpensiveObject expensiveObject;
    private ExpensiveObject moreObjects;
    private String blah;
    private double huh;

    public MegaConstructorBuilder something(String mySomething) {
        this.mySomething = mySomething;
        return this;
    }

    public MegaConstructorBuilder somethingElse(String mySomethingElse) {
        this.mySomethingElse = mySomethingElse;
        return this;
    }

    public MegaConstructorBuilder aConnection(String connection) {
        this.connection = connection;
        return this;
    }

    public MegaConstructorBuilder aPort(int port) {
        this.port = port;
        return this;
    }

    public MegaConstructorBuilder expensiveObject(ExpensiveObject expensiveObject) {
        this.expensiveObject = expensiveObject;
        return this;
    }

    public MegaConstructorBuilder moreObjects(ExpensiveObject moreObjects) {
        this.moreObjects = moreObjects;
        return this;

    }

    public MegaConstructorBuilder blah(String blah) {
        this.blah = blah;
        return this;
    }

    public MegaConstructorBuilder huh(double huh) {
        this.huh = huh;
        return this;
    }

    public MegaConstructor build(){
        return new MegaConstructor(mySomething, mySomethingElse, connection, port, expensiveObject, moreObjects, blah, huh);
    }
}


However this has one major disadvantage; it lacks immutability. I’ve discussed in depth here the benefits of immutability in Java, but in builders it offers a particularly useful benefit- reuse. It is often useful in tests to create a “base” builder with sensible defaults, and then change a couple of key fields. Using the above, we will need to recreate the builder each time as the builder will change.

MegaConstructorBuilder baseBuilder = new MegaConstructorBuilder()
        .something("mySomething")
        .somethingElse("mySomethingElse")
        .aConnection("Http://samatkinson.com")
        .aPort(1234)
        .expensiveObject(new ExpensiveObject())
        .moreObjects(new ExpensiveObject())
        .blah("rah!")
        .huh(1.4);

    MegaConstructor one = baseBuilder.blah("Octopus!").build();
    //This object now has a "blah" of "Octopus!", which could affect our test
    MegaConstructor two = baseBuilder.aPort(9090).build();


Instead, if we use an immutable builder we can reuse our builder over and over without fear of side effects.

private static class MegaConstructorBuilder {
//Primitives must be wrapped to allow null values
      private final String mySomething;
    private final String mySomethingElse;
    private final String connection;
    private final Integer port;
    private final ExpensiveObject expensiveObject;
    private final ExpensiveObject moreObjects;
    private final String blah;
    private final Double huh;

  public MegaConstructorBuilder(){
        this.mySomething = null;
        this.mySomethingElse = null;
        this.connection = null;
        this.port = null;
        this.expensiveObject = null;
        this.moreObjects = null;
        this.blah = null;
        this.huh = null;
  }

    public MegaConstructorBuilder(String mySomething, String mySomethingElse, String connection, int port, ExpensiveObject expensiveObject, ExpensiveObject moreObjects, String blah, double huh) {
        this.mySomething = mySomething;
        this.mySomethingElse = mySomethingElse;
        this.connection = connection;
        this.port = port;
        this.expensiveObject = expensiveObject;
        this.moreObjects = moreObjects;
        this.blah = blah;
        this.huh = huh;
    }

     public MegaConstructorBuilder something(String mySomething) {
        return new MegaConstructorBuilder(mySomething, mySomethingElse, connection, port, expensiveObject, moreObjects, blah, huh);
    }

    public MegaConstructorBuilder somethingElse(String mySomethingElse) {
        return new MegaConstructorBuilder(mySomething, mySomethingElse, connection, port, expensiveObject, moreObjects, blah, huh);

    }

    public MegaConstructorBuilder aConnection(String connection) {
        return new MegaConstructorBuilder(mySomething, mySomethingElse, connection, port, expensiveObject, moreObjects, blah, huh);

    }

    public MegaConstructorBuilder aPort(int port) {
        return new MegaConstructorBuilder(mySomething, mySomethingElse, connection, port, expensiveObject, moreObjects, blah, huh);
        ;
    }

    public MegaConstructorBuilder expensiveObject(ExpensiveObject expensiveObject) {
        return new MegaConstructorBuilder(mySomething, mySomethingElse, connection, port, expensiveObject, moreObjects, blah, huh);

    }

    public MegaConstructorBuilder moreObjects(ExpensiveObject moreObjects) {
        return new MegaConstructorBuilder(mySomething, mySomethingElse, connection, port, expensiveObject, moreObjects, blah, huh);

    }

    public MegaConstructorBuilder blah(String blah) {
        return new MegaConstructorBuilder(mySomething, mySomethingElse, connection, port, expensiveObject, moreObjects, blah, huh);
    }

    public MegaConstructorBuilder huh(double huh) {
        return new MegaConstructorBuilder(mySomething, mySomethingElse, connection, port, expensiveObject, moreObjects, blah, huh);
    }

    public MegaConstructor build(){
        return new MegaConstructor(mySomething, mySomethingElse, connection, port, expensiveObject, moreObjects, blah, huh);
    }
}


Every time we set a parameter we return a brand new instance of MegaConstructorBuilder. We can change it as much as we want with zero side effects.

The only negative is that you have a proliferation of multi-parameter constructors. It’s not nice, but it is hidden from the consumer and centralised in one location, so we can allow this infraction.

Incomplete object protection

Sometimes we can provide sensible default values in the builder for our fields, but normally some if not all fields must be specified by the consumer. In that case we must ensure that all the fields have been set before building, else we must throw an exception (normally an IllegalStateException).

In our build method therefore we must have a whole bunch of null checks before building:

  public MegaConstructor build() {
        if (mySomething != null &&
            mySomethingElse != null &&
            connection != null &&
            port != null &&
            expensiveObject != null &&
            moreObjects != null &&
            blah != null &&
            huh != null)
            return new MegaConstructor(mySomething, mySomethingElse, connection, port, expensiveObject, moreObjects, blah, huh);
        else throw new IllegalStateException("MegaConstructorBuilder fields contained null values \n" + this.toString());
    }

    @Override
    public String toString() {
        return "MegaConstructorBuilder{" +
            "mySomething='" + mySomething + '\'' +
            ", mySomethingElse='" + mySomethingElse + '\'' +
            ", connection='" + connection + '\'' +
            ", port=" + port +
            ", expensiveObject=" + expensiveObject +
            ", moreObjects=" + moreObjects +
            ", blah='" + blah + '\'' +
            ", huh=" + huh +
            '}';
    }


This is the lazy version; it would be better to have each field have an individual null check, and if it fails append it to an error log which is thrown.

 public MegaConstructor build() {
        String error = "";
        if(mySomething != null){ error+= "mySomething is null\n"; }
        if(mySomethingElse != null){ error+= "mySomethingElse is null\n"; }
        if(connection != null){ error+= "connection is null\n"; }
        if(port != null){ error+= "port is null\n"; }
        if(expensiveObject != null){ error+= "expensiveObject is null\n"; }
        if(moreObjects != null){ error+= "moreObjects is null\n"; }
        if(blah != null){ error+= "blah is null\n"; }
        if(huh != null){ error+= "huh is null\n"; }

        if(error.length() > 0) throw new IllegalStateException("MegaConstructorBuilder fields contained null values \n" + error);

        return new MegaConstructor(mySomething, mySomethingElse, connection, port, expensiveObject, moreObjects, blah, huh);
    }


It is important not to throw the error on the first incorrect data; By finding all null fields it allows the user to correct all issues without having to fix field by field and then re-running to see if the problem is fixed.

CA App Experience Analytics, a whole new level of visibility. Learn more. Brought to you in partnership with CA Technologies.

Topics:
java ,builder ,design patterns

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}