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
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Making fields final and the constructor private guarantees an object can't be mutated or built in an invalid partial state.
- 2A fluent Builder that returns this lets callers set only the fields they need in any order before a single build call.
- 3Returning Optional for a nullable field signals its absence in the type itself instead of forcing callers to null-check.
Related explainers
java
public record AppConfig( String host, int port, String databaseUrl,
Loading typed config from env vars in Java
records
configuration
environment-variables
Intermediate
6 steps
php
<?php namespace App\Validation;
Building a reusable address form validator in PHP
validation
error-accumulation
regex
Intermediate
9 steps
java
public class RequestThrottler { private final Semaphore permits; private final long acquireTimeoutMillis;
Bounding concurrency with a Semaphore in Java
concurrency
semaphore
rate-limiting
Intermediate
6 steps
php
<?php namespace App\Http\Controllers;
A cached autocomplete endpoint in Laravel
caching
validation
query-ranking
Intermediate
8 steps
java
public List<DailySample> backfillMissingDates(List<DailySample> samples, double fillValue) { if (samples.isEmpty()) { return List.of(); }
Backfilling gaps in a daily time series in Java
streams
time-series
treemap
Intermediate
5 steps
java
public final class Ulid { private static final char[] ENCODING = "0123456789ABCDEFGHJKMNPQRSTVWXYZ".toCharArray(); private static final SecureRandom RANDOM = new SecureRandom();
How to generate a ULID in Java
base32-encoding
bit-manipulation
identifiers
Intermediate
8 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/building-immutable-objects-with-the-builder-pattern-explained-java-a57e/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.