Course contents

Immutable collections

Immutable, unmodifiable and fixed-size collection variants, factory methods, stream collectors, UnsupportedOperationException, shallow immutability and defensive copies.

PremiumMust know for interviewsLesson13 min readCoreReviewed Oct 2026 · Java 21
On this page
  1. Picture it first: window, snapshot, printed menu
  2. Three tiers under the hood: view, copy, factory
  3. Advanced: factory methods, UnsupportedOperationException and streams
  4. Shallow immutability and defensive copies
  5. Comparing the variants
  6. How to say it in the interview

🧊 What are immutable collections?

An immutable collection is a collection whose membership cannot change after it is created: no add, no remove, no set, no hidden backing list that can later mutate it. It acts like a printed menu: customers can read it all day, but changing tonight's specials means printing a new menu. In Java, List.of("standard", "express") is immutable; Collections.unmodifiableList(source) is only a read-only window over source.

For this lesson, we'll focus on the three tiers you need in interviews and code review: unmodifiable views, unmodifiable copies and Java's immutable factory collections. We'll also cover Arrays.asList, UnsupportedOperationException, immutable map implementations, stream collectors, shallow immutability, defensive copies and performance notes. Interviewers love this one because the words sound interchangeable until a production object changes behind your back.

Below the line (out of scope)

The 30-second answer

There are three different things people call immutable. Collections.unmodifiableList(list) is an unmodifiable view: writes through the view throw, but changes to the backing list show through. List.copyOf(list) is an unmodifiable copy: it snapshots the elements, rejects null, and may return the same instance if the input is already one of the JDK's immutable lists. List.of, Set.of, Map.of and Map.ofEntries are Java 9 immutable factory collections: no nulls, duplicate set elements or map keys throw IllegalArgumentException, and Map.of has overloads up to 10 key-value pairs. Arrays.asList is neither resizable nor immutable: set works, add throws. Stream toList() is unmodifiable and allows nulls; Collectors.toList() gives no mutability guarantee; Collectors.toUnmodifiableList() rejects nulls. All of these are shallow, so mutable elements can still change.

What you’ll learn

  • Separate unmodifiable views, unmodifiable copies and true immutable factory collections
  • Explain why Collections.unmodifiableList can still change when its backing list changes
  • Debug Java List UnsupportedOperationException from Arrays.asList, List.of, Stream.toList and wrapper collections
  • Use Java convenience factory methods: List.of, Set.of, Map.of and Map.ofEntries
  • Collect a Java Stream to an immutable collection with toList, toUnmodifiableList and copyOf
  • Write defensive copies in constructors and getters, and remember immutable collections are shallow

Interview radar

Must-know: Why does add throw UnsupportedOperationException on a list I can still set? Core follow-up: What changes if the original list is modified after Collections.unmodifiableList versus List.copyOf? Production angle: A supposedly immutable config object changes because its constructor kept the caller's mutable ArrayList.

01Picture it first: window, snapshot, printed menu

Let's get the picture right first. An unmodifiable view is a window into someone else's room: you cannot move furniture through the window, but if the owner moves a chair, you see it. An unmodifiable copy is a photo taken once. An immutable factory collection is closer to a printed menu built for sharing.

Fig. 1

A mutable source list feeds three variants: an unmodifiable view that still sees source changes, a copy that does not, and an immutable factory list that has no source

A mutable source list feeds three variants: an unmodifiable view that still sees source changes, a copy that does not, and an immutable factory list that has no source

Notice the source arrow. The view keeps pointing at the original collection. The copy and factory collection do not, although they still point at the same element objects unless you copy those too.

02Three tiers under the hood: view, copy, factory

The simple option is a wrapper. It stops writes through your reference and is cheap to create. It stops being enough when the original collection can still be mutated somewhere else, which is most API boundaries.

Try it yourself first

Before reading the output, decide which lists print the new "refund" value after source.add.

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

public class ImmutableTiersDemo {
    public static void main(String[] args) {
        List<String> source = new ArrayList<>(List.of("card", "cash"));

        List<String> view = Collections.unmodifiableList(source);
        List<String> copy = List.copyOf(source);
        List<String> factory = List.of("card", "cash");

        source.add("refund");

        System.out.println(view);       // [card, cash, refund]
        System.out.println(copy);       // [card, cash]
        System.out.println(factory);    // [card, cash]

        try {
            view.add("wire");
        } catch (UnsupportedOperationException expected) {
            System.out.println("view rejects writes through itself");
        }
    }
}

Notice three things:

  • view is read-only, not independent. It delegates reads to source.
  • copy is independent from later structural changes to source, but it is still shallow.
  • factory never had a mutable source in the first place.

List.copyOf, Set.copyOf and Map.copyOf were added in Java 10. If the input is already one of the JDK's immutable collections, copyOf is allowed to return the same instance. That is good: copying an immutable value again buys nothing.

Premium lesson

Keep reading with the Java Pass

The rest of this lesson is part of Java One-Stop Interview Prep: in-depth explanations, diagrams, model answers and how to say them in the interview.

  • Advanced: factory methods, UnsupportedOperationException and streams
  • Shallow immutability and defensive copies
  • Comparing the variants
  • How to say it in the interview

From ₹199 · one-time payment · No auto-renewal

Practise this topicUtilities & patterns: interview questions & scenarios
Further reading (9)