mutable vs immutable java
Java

Mutable vs Immutable Classes in Java: Complete Guide

Introduction: Why This Topic Matters

When working with Java, one of the fundamental design choices you’ll encounter is whether to make your classes mutable or immutable. This decision affects everything from performance and memory management to thread safety and system design. Many developers treat it as a minor detail, but in reality, it can make or break the reliability of your code.

Everyday Coding Scenarios

Think about these common cases:

  • You’re storing objects as keys in a HashMap.
  • You’re writing code that will run across multiple threads.
  • You’re designing a value object like a Date, Money, or UserProfile.

In each of these situations, whether the class is mutable or immutable directly impacts correctness and maintainability.

Why Interviewers Love This Topic

Mutable vs immutable is a favorite in Java interviews because it tests both core language knowledge and design thinking. Candidates are often asked to explain the concept, justify design choices, or even write code on the spot.

Sample Interview Question

What is the difference between a mutable and immutable class in Java?

This is usually one of the first questions interviewers ask when testing a candidate’s fundamentals. A strong answer shows that you not only understand Java at the surface level but can also reason about thread safety, performance, and real-world use cases.

What You’ll Learn in This Post

In this guide, we’ll break down:

  • What mutability and immutability mean in Java.
  • Practical examples of both.
  • Pros, cons, and trade-offs.
  • How to implement your own immutable classes.
  • Real-world scenarios and interview-focused insights.

By the end, you’ll not only know the difference—you’ll also know when and why to choose one over the other.

What Does “Mutable” Mean in Java?

A mutable class in Java is one whose internal state can be changed after the object is created. In other words, if you create an instance of such a class, you can modify its fields later without creating a new object.

Characteristics of Mutable Classes

  • Fields can be reassigned or updated.
  • Usually provide setter methods or other mutator methods.
  • The same object reference can represent different states at different times.
  • Require careful handling in multi-threaded environments, as concurrent modifications can lead to race conditions.

Common Examples in the JDK

Some of the most widely used mutable classes in Java include:

  • StringBuilder – allows you to append, delete, or modify characters.
  • ArrayList – lets you add, remove, or replace elements dynamically.
  • HashMap – you can keep updating key-value pairs as needed.

These classes are highly useful because they provide flexibility and efficiency when frequent changes are required.

A Simple Example

class Person {
    private String name;
    private int age;

    // Constructor
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // Setter methods allow mutation
    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    // Getter methods
    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

// Usage
Person p = new Person("Alice", 25);
p.setAge(30); // Mutating the object

Here, the Person object starts with age = 25, but later, the age can be changed to 30. This makes the class mutable.

Risks of Mutability

  • Concurrency issues: Two threads updating the same object at once can cause inconsistent states.
  • Harder debugging: Since the same object can change multiple times, tracking issues becomes tricky.
  • Unsafe as keys in collections: If the fields that define equality (hashCode/equals) change after insertion, objects may get “lost” inside HashMap or HashSet.

Sample Interview Question

Can you give examples of mutable classes from the JDK?

A good answer would mention StringBuilder, ArrayList, and HashMap, followed by a short explanation of how each allows changes to its internal state.

What Does “Immutable” Mean in Java?

An immutable class in Java is one whose state cannot be changed once the object is created. All fields are assigned during object construction, and no method can alter those fields afterward. Instead of modifying an existing object, any “change” results in the creation of a new object.

Characteristics of Immutable Classes

  • All fields are declared final and assigned only once.
  • No setter methods or mutators are provided.
  • Often the class itself is declared final to prevent subclassing.
  • Any mutable fields inside are defensively copied to ensure external code cannot alter the object.
  • Naturally thread-safe, since their state cannot change.

Common Examples in the JDK

Some of the most widely used immutable classes include:

  • String – once created, its contents never change.
  • Wrapper classes: Integer, Double, Boolean.
  • New Date/Time API: LocalDate, LocalDateTime, ZonedDateTime.

A Simple Example

final class ImmutablePerson {
    private final String name;
    private final int age;

    // Constructor initializes all fields
    public ImmutablePerson(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // Only getters, no setters
    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

// Usage
ImmutablePerson p = new ImmutablePerson("Alice", 25);
// p.setAge(30); // Not possible – no setter

Here, once the ImmutablePerson object is created with age = 25, it cannot be changed. If you want a Person with age = 30, you must create a new object.

Why Java String is Immutable

The immutability of String is a classic interview question. Reasons include:

  • Security: Strings are often used in class loading, database URLs, and file paths. If mutable, they could be altered after validation.
  • Caching: String literals are stored in a string pool. Immutability allows safe sharing across multiple references.
  • Thread safety: Multiple threads can safely use the same String without synchronization.

Sample Interview Question

Why is String immutable in Java?

A strong answer should cover security, string pool optimization, and thread safety as the main reasons.

Real-World Analogies

Sometimes, the best way to understand a programming concept is through simple real-life comparisons. Mutable and immutable classes in Java can be explained with objects we interact with every day.

Analogy for Mutable Objects

A mutable object is like a whiteboard. You can write something, erase it, and rewrite it. The same whiteboard changes its content multiple times, but it’s still the same board.

Other real-life examples:

  • A text document in Microsoft Word: you can edit and save it repeatedly.
  • A car’s dashboard settings: you can change the temperature, radio station, and volume anytime.

In Java terms, classes like ArrayList or StringBuilder behave this way—you change their contents, but the reference to the object remains the same.

Analogy for Immutable Objects

An immutable object is like writing with a permanent marker on paper. Once you’ve written something, you can’t erase or change it. If you want to change the content, you don’t alter the existing paper—you get a new sheet and write again.

Other examples:

  • A printed receipt: once printed, the details never change.
  • Currency notes: you can exchange them, but you don’t change their value or design.

In Java, classes like String and Integer follow this behavior. Every “change” operation creates a brand-new object.

Why These Analogies Help

These comparisons make it easier to reason about when to use each type. If you need something flexible and reusable, a mutable class is like your editable whiteboard. If you want something stable and safe from changes, immutability gives you the permanent-marker guarantee.

Sample Interview Question

How would you explain immutability to a non-programmer?

A strong response would use analogies like a permanent marker vs. whiteboard. Interviewers often look for your ability to simplify complex concepts—especially if you’re aiming for senior or architect roles.

How to Create a Mutable Class in Java

Creating a mutable class in Java is straightforward because it mirrors how most beginners naturally design classes: fields with getters and setters. The defining trait of mutability is that the internal state of an object can be modified after construction.

Basic Steps

  1. Declare instance variables as private.
  2. Provide setter methods to update those variables.
  3. Provide getter methods to read them.
  4. Optionally, allow direct operations that change internal data structures.

Example: A Mutable Person Class

class Person {
    private String name;
    private int age;

    // Constructor
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // Setter methods allow mutation
    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    // Getter methods
    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

// Usage
Person p = new Person("Alice", 25);
p.setAge(30); // Object state changes here

In this example, the Person object starts with age = 25. Later, the setAge method modifies the same object, making it mutable.

Real-World Usage

Mutable classes are often used in:

  • Builders: e.g., StringBuilder for efficient string concatenation.
  • Collections: e.g., ArrayList, HashMap, which are designed to be updated frequently.
  • UI State Objects: when values change dynamically during user interaction.

Risks of Mutable Classes

While mutability makes objects flexible, it introduces potential issues:

  • Concurrency hazards: If multiple threads update the same object, race conditions can occur.
  • Debugging complexity: Since the same object can represent multiple states, tracking its history becomes harder.
  • Unpredictable collection behavior: If mutable objects are used as keys in HashMap or HashSet, changing their fields that affect hashCode or equals can lead to data “disappearing” from collections.

Sample Interview Question

Why are setter methods considered unsafe in concurrent code?

A good answer would explain that when multiple threads call setters simultaneously, the object’s state may become inconsistent without proper synchronization. This is why immutability is often preferred in multi-threaded environments.

How to Create an Immutable Class in Java

Designing an immutable class requires extra care, but once done correctly, it gives you safety and predictability. Immutable objects are thread-safe by default, can be cached and shared without synchronization, and make your code easier to reason about.

Rules for Creating an Immutable Class

  1. Declare the class as final
    Prevents subclasses from altering immutability guarantees.
  2. Mark all fields as private and final
    Fields must be assigned once and never reassigned.
  3. Initialize fields in the constructor
    The constructor is the only place where values are set.
  4. Do not provide setter methods
    No mutator methods should exist.
  5. Ensure deep immutability
    If a field refers to a mutable object (e.g., Date or List), use defensive copies when assigning and returning them.

Example: Immutable Person Class

import java.util.Date;

public final class ImmutablePerson {
    private final String name;
    private final Date birthDate;

    // Constructor with defensive copy
    public ImmutablePerson(String name, Date birthDate) {
        this.name = name;
        this.birthDate = new Date(birthDate.getTime()); // defensive copy
    }

    // Getter with defensive copy
    public String getName() {
        return name;
    }

    public Date getBirthDate() {
        return new Date(birthDate.getTime()); // defensive copy
    }
}

// Usage
Date date = new Date();
ImmutablePerson p = new ImmutablePerson("Alice", date);

// Even if we change 'date', ImmutablePerson stays safe
date.setTime(0);  
System.out.println(p.getBirthDate()); // Still original birth date

In this example:

  • The class is declared final.
  • All fields are private and final.
  • Defensive copies prevent external modification of the birthDate.

Real-World Usage

Immutable classes are widely used in:

  • Value objects: like String, Integer, BigDecimal.
  • Date/Time APIs: Java 8’s LocalDate, LocalTime, etc.
  • Concurrency scenarios: safe sharing across threads without locks.

Benefits of Following These Rules

  • Thread safety: no synchronization required.
  • Predictability: once constructed, the object’s state is fixed.
  • Safe in collections: immutable keys never “disappear” from maps or sets.

Sample Interview Question

What design principles are followed when creating immutable classes in Java?

A strong answer would mention:

  • final class, final fields, no setters, defensive copies, and constructor initialization. Bonus points if you also mention immutability in the context of thread safety and caching.

Pros and Cons of Mutable Classes

Mutable classes are everywhere in Java because they provide flexibility. However, that flexibility comes with trade-offs, especially in concurrent or large-scale systems. Understanding both sides helps you decide when mutability is the right tool.

Advantages of Mutable Classes

  • Flexibility
    You can update fields, add elements, or modify state without creating new objects.
  • Performance efficiency (sometimes)
    When you need to perform frequent modifications, mutability saves memory and CPU time by avoiding constant object creation. For example, StringBuilder is much faster than String when concatenating in loops.
  • Natural modeling
    Many real-world entities change over time. For example, a BankAccount balance or a UserSession naturally evolves during execution.

Disadvantages of Mutable Classes

  • Thread-safety issues
    Mutable classes are prone to race conditions if accessed by multiple threads without proper synchronization.
  • Harder to reason about
    Since the same reference can represent different states at different times, debugging and testing become more difficult.
  • Unsafe in collections
    If mutable objects are used as keys in a HashMap or elements in a HashSet, modifying fields that affect hashCode or equals can make them “disappear” from the collection.

Example: Mutable Key in a HashMap

import java.util.HashMap;

class MutableKey {
    private String id;

    public MutableKey(String id) {
        this.id = id;
    }

    public void setId(String id) {
        this.id = id;
    }

    @Override
    public int hashCode() {
        return id.hashCode();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof MutableKey)) return false;
        MutableKey other = (MutableKey) o;
        return id.equals(other.id);
    }
}

public class MutableDemo {
    public static void main(String[] args) {
        HashMap<MutableKey, String> map = new HashMap<>();
        MutableKey key = new MutableKey("123");
        map.put(key, "Value");

        // Mutating the key
        key.setId("456");

        // Now retrieval fails
        System.out.println(map.get(key)); // null
    }
}

Here, once the key is modified, the map can no longer find the entry because the hashCode has changed.

When Mutability Shines

  • Data structures that change frequently (ArrayList, HashMap).
  • Builders (StringBuilder) where performance is critical.
  • Models of evolving state, such as games or simulations.

Sample Interview Question

Why are mutable classes harder to use as keys in HashMaps?

The correct answer should explain that if the fields used in hashCode or equals are modified after insertion, the object may not be found in the correct bucket, effectively breaking the contract of the map.

Pros and Cons of Immutable Classes

Immutable classes are increasingly popular in modern Java design. They simplify reasoning about code and are a cornerstone of functional programming. But like every design choice, they come with trade-offs you should weigh carefully.

Advantages of Immutable Classes

  • Thread safety by default
    Since the state never changes, immutable objects can be safely shared across multiple threads without synchronization.
  • Safe for caching and collections
    Objects don’t change after creation, making them perfect as keys in HashMap or elements in HashSet.
  • Easier debugging and reasoning
    The state is predictable. Once you see how an object was created, you know it will stay that way forever.
  • Security benefits
    Immutable objects can’t be tampered with once validated, making them ideal for sensitive use cases like String in class loading or database URLs.
  • Functional programming alignment
    Java’s newer APIs (streams, lambda expressions, Java Time API) encourage immutability for cleaner, side-effect-free code.

Disadvantages of Immutable Classes

  • Object creation overhead
    Every “change” creates a new object. For small updates in tight loops, this may hurt performance.
  • Memory consumption
    Large immutable objects with frequent modifications can generate a lot of short-lived objects, putting pressure on the garbage collector.
  • Inflexibility
    For certain models where state naturally changes (e.g., a BankAccount), immutability feels unnatural or overly restrictive.

Example: Inefficient Use of Immutability

public class StringDemo {
    public static void main(String[] args) {
        String result = "";
        for (int i = 0; i < 10000; i++) {
            result += i; // creates a new String each time!
        }
        System.out.println(result.length());
    }
}

Here, every iteration creates a new String object because String is immutable. This is why StringBuilder (mutable) is used instead in performance-critical concatenation scenarios.

When Immutability Shines

  • Keys in collections – reliable and safe.
  • Multithreaded applications – no synchronization headaches.
  • Value objectsMoney, Date, Coordinates are naturally immutable.
  • Domain-driven design – immutability helps enforce business rules at the object level.

Sample Interview Question

If immutability is so good, why don’t we make everything immutable?

A strong answer should highlight the trade-offs: while immutability provides thread-safety and predictability, it can also cause performance and memory issues when frequent updates are required. That’s why mutable structures like StringBuilder and ArrayList exist.

When to Use Mutable vs Immutable

Knowing the theory is one thing, but the real skill lies in deciding when to design classes as mutable and when to prefer immutable. Both have their place, and choosing the right one depends on context.

When to Use Mutable Classes

  • Frequent updates are required
    If the object changes constantly (like a buffer or cache), mutability avoids creating thousands of new objects.
    Example: StringBuilder for string concatenation in loops.
  • Performance-sensitive scenarios
    Large collections or data models that evolve rapidly benefit from mutability to reduce object creation overhead.
  • Modeling evolving state
    Some objects naturally represent entities that change over time.
    Example: A BankAccount balance, or a UserSession in a web application.

When to Use Immutable Classes

  • Value objects
    If your class represents a simple value, immutability makes sense.
    Example: Money, Coordinates, LocalDate.
  • Multithreaded applications
    Immutable objects eliminate synchronization concerns, making them safe for concurrent access.
  • Keys in collections
    Immutable keys in HashMap or elements in HashSet prevent surprises when fields used in equals and hashCode never change.
  • Functional programming style
    If you’re writing code with streams, lambdas, or functional transformations, immutability leads to cleaner and more predictable results.

General Guideline

  • Prefer immutability by default.
    Start by designing objects as immutable unless there’s a strong reason to make them mutable.
  • Use mutability deliberately.
    When performance, flexibility, or natural domain modeling demands it, mutability becomes the right choice.

Example Decision

  • Designing a UserProfile object for authentication → Immutable (since once created, the user’s identity should not change).
  • Designing a ShoppingCart that updates as the user adds items → Mutable (since it evolves during the session).

Sample Interview Question

How do you decide when to use a mutable or immutable class?

A good answer explains the trade-off:

  • Choose immutable for thread-safety, stability, and predictability.
  • Choose mutable when frequent state changes or performance concerns justify it.

Conclusion and Takeaways

Mutable and immutable classes are two sides of the same coin in Java programming. Each has its own strengths, weaknesses, and ideal use cases. As a developer, your ability to choose between them—and explain why—is a strong signal of design maturity.

Key Points to Remember

  • Mutable classes
  • State can change after object creation.
  • Flexible and often more performant for frequent updates.
  • Risky in multi-threaded environments without synchronization.
  • Immutable classes
  • State is fixed once constructed.
  • Naturally thread-safe and great for value objects.
  • May cause performance or memory overhead if misused.

Best Practice

  • Prefer immutability by default. It simplifies code, enhances thread safety, and reduces bugs.
  • Use mutability only when necessary. Builders, caches, and evolving states are good candidates.

Final Interview Question

What are the top three benefits of immutability in Java?

An ideal answer:

  1. Thread-safety without synchronization.
  2. Safe and predictable use in collections.
  3. Easier debugging and reasoning about code.

By mastering these concepts, you’ll not only write better Java code but also impress interviewers who want to see clear thinking and solid design instincts.