Java

Immutable Collections in Java

Understand List.of(), Set.of(), Map.of(), unmodifiable wrappers, shallow immutability, and common interview follow-ups.

JavaCollectionsImmutabilityListMap

The Short Version

Immutable collections cannot be structurally modified after they are created. In Java, methods like List.of(), Set.of(), and Map.of() create truly unmodifiable collection instances.

Interviewers usually want to know the difference between immutable collections, unmodifiable wrappers, and normal mutable collections.

Basic Examples

java
import java.util.List;
import java.util.Map;
import java.util.Set;

public class ImmutableCollectionsExample {

    public static void main(String[] args) {
        List<String> names = List.of("Alice", "Bob", "Charlie");

        Set<String> roles = Set.of("ADMIN", "USER");

        Map<String, Integer> scores = Map.of(
            "Alice", 95,
            "Bob", 88
        );

        // Throws UnsupportedOperationException
        names.add("David");
    }
}

These collections are useful when you want a small fixed collection that should not change after creation.

What Happens If You Modify It?

If you try to add, remove, or update entries in these collections, Java throws UnsupportedOperationException.

java
List<String> names = List.of("Alice", "Bob");

names.add("Charlie"); 
// java.lang.UnsupportedOperationException
Immutable collection means the collection structure cannot change: no add, remove, clear, or replace operations.

Immutable Collection vs Unmodifiable Wrapper

This is one of the most important interview distinctions.

List.of() creates an unmodifiable collection directly. But Collections.unmodifiableList() creates a wrapper around an existing list.

java
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

List<String> mutable = new ArrayList<>();
mutable.add("A");
mutable.add("B");

List<String> wrapper = Collections.unmodifiableList(mutable);

// This fails
wrapper.add("C");

// But this still changes what wrapper sees
mutable.add("C");

System.out.println(wrapper); // [A, B, C]
An unmodifiable wrapper prevents changes through the wrapper reference, but the original underlying collection may still be mutable.

Important Details

Nulls Are Not Allowed

List.of(), Set.of(), and Map.of() do not allow null elements, null keys, or null values.

Duplicates Are Not Allowed in Set.of

Set.of() throws an exception if duplicate elements are provided.

Map.of Has Limits

Map.of() is convenient for small maps. For many entries, use Map.ofEntries().

Not Deeply Immutable

If the collection contains mutable objects, those objects can still be changed.

Shallow Immutability

Immutable collections prevent the collection itself from changing, but they do not automatically make the objects inside immutable.

java
class User {
    String name;

    User(String name) {
        this.name = name;
    }
}

User user = new User("Alice");

List<User> users = List.of(user);

// This fails
users.add(new User("Bob"));

// But this still works
user.name = "Updated Alice";
The list is immutable, but the User object inside the list is still mutable.

When Would You Use Immutable Collections?

  • Fixed configuration values
  • Constants
  • Small lookup tables
  • Safe return values from methods
  • Reducing accidental modification
  • Sharing read-only data across code

What Interviewers Are Looking For

You Know the APIs

You can mention List.of(), Set.of(), Map.of(), and Map.ofEntries().

You Understand Failures

You know modification attempts throw UnsupportedOperationException.

You Know Wrapper Behavior

You can explain why Collections.unmodifiableList() is not the same as creating a truly independent immutable collection.

You Understand Shallow Immutability

You know immutable collections do not make mutable elements immutable.

Common Follow-Ups

Are immutable collections thread-safe?

They are safe from structural modification, which makes them easier to share. But if they contain mutable objects, those objects can still cause thread-safety problems.

What is the difference between List.of() and Arrays.asList()?

List.of() creates an unmodifiable list and does not allow nulls. Arrays.asList() returns a fixed-size list backed by the array, so set() works but add() and remove() do not.

Can Map.of() contain null keys or values?

No. Map.of() rejects null keys and null values.

Final Takeaway

For interviews, say this clearly: immutable collections prevent structural changes, unmodifiable wrappers only block changes through the wrapper, and mutable objects inside the collection may still be changed.