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
php
<?php namespace App\Services\Checkout;
Validating coupons with Laravel's Pipeline
pipeline
chain of responsibility
transactions
Intermediate
7 steps
java
@Component @Converter public class EncryptedStringConverter implements AttributeConverter<String, String> {
Transparent column encryption in Spring & JPA
encryption
aes-gcm
jpa-converter
Advanced
10 steps
php
<?php namespace App\Services;
How a password strength validator works in PHP
validation
regular-expressions
data-driven
Intermediate
8 steps
java
package com.acme.billing.config; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.ConfigurationProperties;
Feature-flagged beans with Spring @ConditionalOnProperty
feature-flags
conditional-beans
strategy-pattern
Intermediate
5 steps
rust
use chrono::{Duration, NaiveDate}; #[derive(Debug)] pub struct DateRange {
Parsing and iterating date ranges in Rust
error-handling
iterators
parsing
Intermediate
7 steps
java
public static Map<String, String> parseCookieHeader(String header) { Map<String, String> cookies = new LinkedHashMap<>(); if (header == null || header.isBlank()) { return cookies;
Parsing an HTTP Cookie header in Java
string-parsing
http
url-decoding
Intermediate
6 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.