Java ProgramsCollectionsImmutable Map

Immutable Map in Java

beginner·  Collections  ·  Immutability

Problem

Map.of() (Java 9+) builds a Map that can never be modified after creation, following the same immutability guarantee as List.of() and Set.of().

Create a Map of key-value pairs that can never be added to, removed from, or changed after it's built.

Input
Map.of("a", 1, "b", 2, "c", 3)
Output
Value for b: 2

Java Program

Java
import java.util.Map; public class ImmutableMapDemo { public static void main(String[] args) { Map<String, Integer> scores = Map.of("a", 1, "b", 2, "c", 3); System.out.println("Value for b: " + scores.get("b")); // scores.put("d", 4) here would throw UnsupportedOperationException } }

Output

Value for b: 2

Core Logic

Passing alternating key-value arguments to Map.of() builds an immutable map directly, without a mutable HashMap ever existing in between.

How It Works
  1. 1Map.of("a", 1, "b", 2, "c", 3) takes its arguments as alternating key, value, key, value pairs.
  2. 2The returned map supports normal reads — get(), containsKey(), iteration — exactly like a regular Map.
  3. 3Calling a mutating method like .put(...) throws UnsupportedOperationException, the same guarantee as List.of() and Set.of().
  4. 4Duplicate keys among the arguments throw IllegalArgumentException at construction, just as Set.of() rejects duplicate elements.
Map.of("a", 1, "b", 2, "c", 3).get("b") returns 2.
💡

Key Point: The alternating key-value argument list gets unwieldy for a map with many entries — Map.ofEntries(Map.entry("a", 1), Map.entry("b", 2), ...) is the alternative for those cases, taking a list of key-value pairs instead of one long flat argument list.

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

Why: Map.of() stores each of the n given key-value entries once, after checking for duplicate keys among them.

Key Concepts

Map.of()immutabilityMap.ofEntries()

Approach 2: Java 8

Java
import java.util.Map; import java.util.stream.Collectors; public class ImmutableMapStream { public static void main(String[] args) { Map<String, Integer> source = Map.of("a", 1, "b", 2, "c", 3); // Doubles each value while collecting into a genuinely immutable map Map<String, Integer> doubled = source.entrySet().stream() .collect(Collectors.toUnmodifiableMap(Map.Entry::getKey, e -> e.getValue() * 2)); System.out.println("Value for b: " + doubled.get("b")); // doubled.put("d", 8) here would throw UnsupportedOperationException } }

Output

Value for b: 4

Core Logic

Collectors.toUnmodifiableMap() builds an immutable map from a stream pipeline directly, for the common case where the entries are derived from existing data rather than being known ahead of time as literals.

How It Works
  1. 1source.entrySet().stream() opens a stream over an existing mutable map's entries.
  2. 2Collectors.toUnmodifiableMap(Map.Entry::getKey, e -> e.getValue() * 2) builds a new map, keeping each original key but doubling its value — something Map.of() can't express, since it just takes fixed key-value pairs directly.
  3. 3The result carries the same immutability guarantee as Map.of() — a put() call on it throws UnsupportedOperationException.
  4. 4The original source map is left completely unmodified.
Doubling the values of {a=1, b=2, c=3} and collecting produces the immutable map {a=2, b=4, c=6}, so get("b") returns 4.
💡

Key Point: Map.of() is for entries already known as literals; Collectors.toUnmodifiableMap() is for the more common real-world case — an immutable map built from data that was transformed or derived from another map first.

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

Why: The stream visits each of the source map's n entries once, and collect() builds a new immutable map to hold the transformed entries.

Key Concepts

StreamCollectors.toUnmodifiableMap()

Related Programs