The Builder Pattern in Java With the Least Code Possible

Immutable objects are important to make your code more robust, especially in days of more parallelization. A builder pattern is used when some of the variables of an immutable class are required and some are optional. But this leads to a massive constructor explosion, at least in Java. Today I think I found an improved builder pattern which could be used with no attribute duplication in the builder class and no separate private constructor in the domain class.

Usual Constructors

Here is a normal immutable class with the various necessary constructors for only one optional field ‘age’:

public class Person {
  private final String name; // required
  private final int age;     // optional

  public Person(String name, int age) {
     this.name = name;
     this.age = age;
  }
  public Person(String name) {
     this.name = name;
  }
  public Person(int age) {
     this.age = age;
  }

  public String getName() {
     return this.name;
  }
  public int getAge() {
     return age;
  }
}

Builder Pattern 1.0

The builder pattern removes the need of various constructor combinations:

public class Person {
  private final String name; // required
  private final int age;     // optional
  private Person(PersonBuilder pb) {
     this.age = pb.age;
     this.name = pb.name;
  }

  public String getName() {
     return this.name;
  }
  public int getAge() {
     return age;
  }
}

public class PersonBuilder {
  private String name;
  private int age;

  public PersonBuilder name(String name) {
     this.name = name;
     return this;
  }
  public PersonBuilder age(int age) {
     this.age = age;
     return this;
  }

  public Person create() {
     return new Person(this);
  }
}

The usage is:

Person p = new PersonBuilder().
   name("testing").
   age(20).
   create();

Builder Pattern 2.0

Now my builder pattern with less overhead. Of course in real world examples you won’t have only one optional field making the savings more obvious. The Builder Pattern 2.0 uses a static embedded subclass for the builder and still uses (package) protected fields. As you can see this solution is only ~5 lines more than the original immutable object without the constructors as it just moves the setters into a separate class:

public class Person {
  String name; // required
  int age;     // optional

  public String getName() {
     return this.name;
  }
  public int getAge() {
     return age;
  }

  public static class BEGIN extends Person {
    public BEGIN name(String name) {
      this.name = name;
      return this;
    }
    public BEGIN age(int age) {
      this.age = age;
      return this;
    }

    public Person END() {
      return this;
    }
  } // end of builder class
} // end of domain class

The usage is similar to the original builder pattern:

Person p = new Person.BEGIN().
   name("testing").
   age(20).
   END();

Keep in mind that this solution has the ‘drawback’ of no unnecessary object creation involved like builder pattern 1.0. And therefor the END method is not thread-safe unlike the create method. (You can fix that via this.clone() within END, not sure if you like that). Also I think for those cases you probably need more something like a factory. As noted in the comments the builder class START should be renamed to Builder and then even better create a public static method ala ‘Builder Start() { return new Builder(); }’ where you then can avoid the ‘new’ when using it.

Improvement: Builder Pattern 2.1

After the comments and having this implemented in production I observed drawbacks. E.g. that you don’t have to call the END method at all as the subclass is also accepted. And that you could theoretically just downcast a Person object to its builder and change the variables again. The simplest solution is to use composition instead of inheritance like we do with our AlgorithmOptions object at GraphHopper, this way we can also use private fields again.

Conclusion

This new builder pattern is suited if a method has several arguments with some of them optional. You can move these arguments into a separate class and use this pattern to avoid code duplication like I’ll probably do for some classes in GraphHopper. For everyone in love with magic (unlike me) they can also have a look into the project lombok as noted in the comments. Still the best thing would be to have something like this directly in Java and being able to write:

Person p = new Person(name="testing", age=20);

9 thoughts on “The Builder Pattern in Java With the Least Code Possible

  1. Yes, sure. But I forgot to mention that I dislike every magic. Also the IDE would need support for this or slower compile-debug circle or whatever.

  2. I typically add a static method to avoid having to type new. So, Person.start().name(‘foo’).end().

    The start/end convention is a matter of taste I guess. I tend to go for something more descriptive. Also BEGIN and END are violating java naming guidelines since they are not constants.

    Another neat trick is to support the builder instance in other builders so that you don’t have to type end()/build()/create(). I do this in JsonJ where object().put(”nested”, object().put(“foo”,”bar”)).build() produces the same as object().put(”nested”, object().put(“foo”,”bar”).build()).build().

    Finally, once you have static methods create the builder, it is tempting to add a few more that provide you a short cut for having to type all method names for the required fields.

    so Person p = Person.person(“yours truly”, 40, “m”); is a lot nicer than new Person.BEGIN().name(“yours truly”).age(40),hmmm(“m”).end().

    The DRY principle is a good guide here and polymorphism is your best friend.

    So back to my jsonj example, the following would also work: object(field(“nested”, object(field(“foo”,”bar”)). No new, no builder, just static methods.

  3. The BEGIN and END is not really nice, I chose them to make it obvious in the first place. Maybe begin() and end() OR just builder() and build() like in project lombok.

    Avoiding ‘new’ via a static method is a good idea.

    I don’t understand what you mean with Person.person(“yours truly”, 40, “m”) because that is exactly the constructor I want to avoid?

  4. You wrote that you don’t like any magic, but I it can save you a lot of work🙂

    However, I personally don’t like the magic of Lombok either. It’s because it uses internal compiler API to achieve its goals.

    Maybe you want to give PojoBuilder a try. It’s build on top of the standard annotation processing API: https://github.com/mkarneim/pojobuilder

Comments are closed.