Immutable Objects

⭐ Interview Importance: MEDIUM
⏱️ Revision Time: 5 min

TL;DR

  • Immutable Objects are objects whose state (data) cannot be changed after they are constructed (e.g., String, Integer, LocalDate).
  • They are 100% Thread-Safe by default because multiple threads can read them simultaneously without fear of data being modified.
  • To make a class immutable: Make the class final, make all fields private final, and return deep copies of mutable fields (like arrays or lists).

Concept

If a web application shares a User object across 10 threads, and Thread A decides to change the User’s name while Thread B is trying to read it, you get race conditions and corrupted data. You have to use messy synchronized blocks everywhere to prevent this.

If the User object is Immutable, you literally cannot change its data. It has no setter methods. If Thread A wants to change the name, Thread A is forced to create a brand new User object. Therefore, Thread B can read the original User object with zero locking, zero synchronization, and perfect peace of mind. Functional programming relies heavily on immutability.

Examples

import java.util.*;

// 1. Class must be final so children can't override methods and act mutable
public final class ImmutablePerson {
    
    // 2. Fields must be private and final
    private final String name;
    private final List<String> skills; // A mutable collection!

    public ImmutablePerson(String name, List<String> skills) {
        this.name = name;
        // 3. Must perform a DEEP COPY in the constructor. 
        // Otherwise, the caller could modify the original list from the outside!
        this.skills = new ArrayList<>(skills);
    }

    // 4. Provide ONLY Getters. NO SETTERS.
    public String getName() {
        return name;
    }

    public List<String> getSkills() {
        // 5. Must return a COPY (or unmodifiable view) of mutable objects.
        // If we returned the raw list, the caller could do .add() and mutate our state!
        return Collections.unmodifiableList(skills);
    }
}

Interview Questions

Q: If Immutable objects require creating brand new objects for every change, doesn’t that destroy memory performance?
A: Yes, creating millions of objects does put pressure on the Garbage Collector (which is why string concatenation in loops is bad). However, in modern Java, short-lived object creation in the Young Generation is incredibly cheap, and the GC handles it effortlessly. The minor performance cost is almost always worth it for the massive gains in thread-safety, code predictability, and bug reduction. (Also, immutable objects can be cached aggressively, like the String Pool).

Q: What are Java 14 Records?
A: Records (public record Person(String name, int age) {}) are a new, compact syntax introduced in Java 14. They are designed specifically to act as transparent data carriers. The compiler automatically generates the constructor, getters, equals(), hashCode(), and toString(). Most importantly, all fields in a Record are implicitly final, making the entire Record class natively Immutable by default.