Java ProgramsCollectionsImmutable List

Immutable List in Java

beginner·  Collections  ·  Immutability

Problem

List.of() (Java 9+) builds a List that can never be modified after creation — not a mutable list with restrictions bolted on, but a dedicated immutable implementation.

Create a List of elements that can never be added to, removed from, or changed after it's built.

Input
List.of("Apple", "Banana", "Cherry")
Output
[Apple, Banana, Cherry]

Java Program

Java
import java.util.List; public class ImmutableListDemo { public static void main(String[] args) { List<String> fruits = List.of("Apple", "Banana", "Cherry"); System.out.println(fruits); // fruits.add(...) here would throw UnsupportedOperationException } }

Output

[Apple, Banana, Cherry]

Core Logic

Building the list through the List.of() factory method, instead of a constructor, returns an object whose class doesn't implement mutation at all.

How It Works
  1. 1List.of("Apple", "Banana", "Cherry") returns a List already fully populated with those three elements.
  2. 2The returned object isn't an ArrayList — it's a distinct, package-private implementation whose add/remove/set methods are all deliberately unsupported.
  3. 3Reading from it works exactly like any other List — get(), iteration, and printing all behave normally.
  4. 4Calling any mutating method on it, like .add("Date"), throws UnsupportedOperationException immediately, rather than silently succeeding or failing later.
List.of("Apple", "Banana", "Cherry") prints as [Apple, Banana, Cherry], and reading its elements works normally.
💡

Key Point: This is a genuinely different guarantee from wrapping an existing mutable list — there's no underlying mutable list anywhere for other code to change out from under you, since List.of() never creates one in the first place.

Complexity
Time Complexity: O(n)Space Complexity: O(n)

Why: List.of() stores each of the n given elements once, in a fixed internal structure sized for exactly that many.

Key Concepts

List.of()immutabilityUnsupportedOperationException

Approach 2: Java 8

Java
import java.util.List; import java.util.stream.Collectors; public class ImmutableListStream { public static void main(String[] args) { List<String> source = List.of("Kiwi", "Banana", "Fig", "Cherry"); // Filters first, then collects the result into a genuinely immutable list List<String> longNames = source.stream() .filter(s -> s.length() > 5) .collect(Collectors.toUnmodifiableList()); System.out.println(longNames); // longNames.add(...) here would throw UnsupportedOperationException } }

Output

[Banana, Cherry]

Core Logic

Collectors.toUnmodifiableList() builds an immutable list from a stream pipeline directly, for the common case where the elements come from filtering or transforming existing data rather than being known ahead of time as literals.

How It Works
  1. 1source.stream() opens a stream over an existing mutable source list.
  2. 2.filter(s -> s.length() > 5) narrows the stream down to only the elements meeting some condition — something List.of() can't express, since it just takes a fixed set of elements directly.
  3. 3.collect(Collectors.toUnmodifiableList()) gathers the filtered results into a genuinely immutable list, the same UnsupportedOperationException-on-mutation guarantee List.of() provides.
  4. 4Calling .add(...) on the result throws exactly as it would on a List.of() result.
Filtering [Kiwi, Banana, Fig, Cherry] down to names longer than 5 characters and collecting produces the immutable list [Banana, Cherry].
💡

Key Point: List.of() is for elements already known as literals; Collectors.toUnmodifiableList() is for the more common real-world case — an immutable list built from data that was filtered, mapped, or otherwise derived first.

Complexity
Time Complexity: O(n)Space Complexity: O(n)

Why: filter() visits each of the n source elements once, and collect() builds a new immutable list to hold the surviving elements.

Key Concepts

StreamCollectors.toUnmodifiableList()

Related Programs