×

java · level 3 · unit 7 · lesson 2

  1. meet it
  2. guess first
  3. your turn
  4. fix it
  5. nailed it

Tap a green word if you get lost.

meet it

A collects settings, then builds the object in one go.

A constructor call like new Coffee("latte", 2, "oat", true, false) is unreadable: which true means what? A builder fixes this. A static class Builder inside Coffee keeps the settings, with a named method for each, and anything you never set keeps a sensible default.

Each method sets one field and ends with return this, so calls chain into a sentence: new Coffee.Builder("latte").milk("oat").shots(2).build(). The Coffee constructor is private, so the builder is the only way in.

build() is the place to . It checks the settings and throws IllegalArgumentException with a clear message before a bad object can exist. The finished object can then be immutable, every field final.

public class Main {
    static class Coffee {
        private final String drink;
        private final int shots;
        private final String milk;
        private Coffee(Builder b) { drink = b.drink; shots = b.shots; milk = b.milk; }
        @Override public String toString() { return drink + " (shots: " + shots + ", milk: " + milk + ")"; }
        static class Builder {
            private final String drink;
            private int shots = 1;
            private String milk = "whole";
            Builder(String drink) { this.drink = drink; }
            Builder shots(int count) { shots = count; return this; }
            Builder milk(String type) { milk = type; return this; }
            Coffee build() { return new Coffee(this); }
        }
    }
    public static void main(String[] args) {
        System.out.println(new Coffee.Builder("latte").milk("oat").shots(2).build());
        System.out.println(new Coffee.Builder("flat white").build());
    }
}

The nested Builder may read the private fields of Coffee, and the other way round, because they share one outer class.