java 53 lines · 7 steps

Building immutable objects with the Builder pattern

A final class with a private constructor and a nested Builder produces validated, immutable ShippingAddress instances.

Explained by highlit
1public final class ShippingAddress {
2 private final String recipient;
3 private final String line1;
4 private final String line2;
5 private final String city;
6 private final String postalCode;
7 private final String countryCode;
8 
9 private ShippingAddress(Builder builder) {
10 this.recipient = builder.recipient;
11 this.line1 = builder.line1;
12 this.line2 = builder.line2;
13 this.city = builder.city;
14 this.postalCode = builder.postalCode;
15 this.countryCode = builder.countryCode;
16 }
17 
18 public String recipient() { return recipient; }
19 public String line1() { return line1; }
20 public Optional<String> line2() { return Optional.ofNullable(line2); }
21 public String city() { return city; }
22 public String postalCode() { return postalCode; }
23 public String countryCode() { return countryCode; }
24 
25 public static Builder builder() {
26 return new Builder();
27 }
28 
29 public static final class Builder {
30 private String recipient;
31 private String line1;
32 private String line2;
33 private String city;
34 private String postalCode;
35 private String countryCode;
36 
37 public Builder recipient(String recipient) { this.recipient = recipient; return this; }
38 public Builder line1(String line1) { this.line1 = line1; return this; }
39 public Builder line2(String line2) { this.line2 = line2; return this; }
40 public Builder city(String city) { this.city = city; return this; }
41 public Builder postalCode(String postalCode) { this.postalCode = postalCode; return this; }
42 public Builder countryCode(String countryCode) { this.countryCode = countryCode; return this; }
43 
44 public ShippingAddress build() {
45 Objects.requireNonNull(recipient, "recipient is required");
46 Objects.requireNonNull(line1, "line1 is required");
47 Objects.requireNonNull(city, "city is required");
48 Objects.requireNonNull(postalCode, "postalCode is required");
49 Objects.requireNonNull(countryCode, "countryCode is required");
50 return new ShippingAddress(this);
51 }
52 }
53}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Making fields final and the constructor private guarantees an object can't be mutated or built in an invalid partial state.
  2. 2A fluent Builder that returns this lets callers set only the fields they need in any order before a single build call.
  3. 3Returning Optional for a nullable field signals its absence in the type itself instead of forcing callers to null-check.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Building immutable objects with the Builder pattern — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code