← All articles
Backend1 min read

Immutable Objects in Java

Mutable shared state is the root of most concurrency bugs. Immutable objects are automatically thread-safe and far easier to reason about.

S

Swapnika Voora

Author

An immutable object never changes after construction, so it can be shared across threads with zero locking. This single property eliminates a whole category of bugs.

Build immutability in

Make fields final, do not expose setters, and defensively copy any mutable inputs so callers cannot reach in and change your state.

Money.java
public final class Money {
    private final long cents;
    private final String currency;
 
    public Money(long cents, String currency) {
        this.cents = cents;
        this.currency = Objects.requireNonNull(currency);
    }
 
    public Money plus(Money other) {
        return new Money(this.cents + other.cents, currency);
    }
}

Records make it trivial

For pure data carriers, a record generates the constructor, accessors, and equals for you — all immutable by default.

Point.java
public record Point(int x, int y) {}

Takeaways

  • Return new instances from "mutating" methods instead of changing state.
  • Defensively copy mutable collections on the way in and out.
  • Immutable objects are inherently thread-safe and cache-friendly.

Wrap exposed collections with List.copyOf so callers receive an unmodifiable view they cannot alter.

#java#immutability#concurrency

More in Backend