Tools for values that don't change
final, immutable Strings, final fields with no setters, records, defensive copies, List.of and unmodifiable views.
Pick the tool by what must not change.
- A local variable or a constant →
final(andstatic finalfor a class-wide constant). It fixes the variable, not the object it refers to. - A whole class of values (money, a date range, a point) → a record, or a class with
private finalfields and no setters. - A field that holds a collection or an array → copy it on the way in and on the way out (
List.copyOf,clone), or the caller can still change your object's insides. - A collection you hand out →
List.of/List.copyOffor a true snapshot;Collections.unmodifiableListonly for a read-only VIEW that still shows later changes. - Text → nothing to do:
Stringis already immutable. Keep the returned string.
Variables that can't be reassigned
Term
constant
Example
static final int MAX_SEATS = 120;A static final value fixed at compile time or class load.
Term
final field
Assigned once, in the constructor, never again.
A local that's never reassigned, which is what a lambda may capture.
Objects that can't change
Formal. A String object never changes after it is created. Every
method that seems to modify text, such as toUpperCase, strip,
replace or substring, returns a new String and leaves the original
untouched. A variable can be reassigned to refer to the new string;
the old object is unchanged. == compares references, so text must be
compared with equals (or equalsIgnoreCase).
In plain English. A string is printed on paper, not written on a whiteboard. Asking for an upper-case version prints a fresh sheet. If you don't keep the fresh sheet, by assigning it to a variable, nothing has changed.
Example. After String name = " ada "; name.strip(); the variable
still holds " ada ". name = name.strip(); keeps the result.
"ab-cd".replace("-", "") returns "abcd" and replaces every match.
Why this rule exists. Because no one can change a string behind your back, strings are safe to share and to cache, and to use as lookup keys.
Every String method returns a new string.
Term
immutable
An object whose state never changes after construction.
Section
Getters, setters and when not to
Why a setter for every field gives encapsulation away.
Example
this.items = List.copyOf(items);Copy a mutable argument or field so callers can't reach inside.
Records with compact constructors, copies of mutable components, and 'with' methods.
An object defined by its value, not its identity.
Collections that can't change
List.of, copyOf, and unmodifiable views.
Example
List.of(1, 2).add(3) throws.add and remove throw UnsupportedOperationException.
A list that rejects changes; its elements may still be mutable objects.