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
javascript
export function buildPaginationUrl(baseUrl, { page, perPage, filters = {}, sort } = {}) { const url = new URL(baseUrl); const params = url.searchParams;
Building and parsing pagination URLs
url-parsing
query-string
pagination
Intermediate
8 steps
java
import java.time.Instant; import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter;
Converting timestamps across time zones in Java
date-time
time-zones
instant
Intermediate
6 steps
python
import re from email_validator import validate_email, EmailNotValidError _DISPOSABLE_DOMAINS = {
Normalizing signup emails in Python
validation
normalization
data-cleaning
Intermediate
8 steps
java
package com.example.payments.config; import com.stripe.StripeClient; import org.springframework.beans.factory.annotation.Value;
Swapping payment gateways by profile in Spring
dependency-injection
profiles
configuration
Intermediate
6 steps
go
package validate import ( "fmt"
Struct validation with reflection in Go
reflection
struct-tags
validation
Intermediate
7 steps
python
from datetime import datetime from zoneinfo import ZoneInfo
Timezone-safe datetime handling in Python
timezones
datetime
normalization
Intermediate
4 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.