Java 9 – Factory Methods for Immutable Map: Map.of() and Map.ofEntries()
Before Java 9, creating an immutable map required multiple lines of code: instantiate a HashMap, add entries, then wrap it with Collections.unmodifiableMap(). Java 9 introduced static factory methods — Map.of() and Map.ofEntries() — that let you create unmodifiable maps in a single expression.
This tutorial explains both methods, shows when to use each, and covers important restrictions you need to know before using them in production code.
The Old Way (Pre-Java 9)
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
// Creating an immutable map before Java 9 – 5 lines
Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 95);
scores.put("Bob", 87);
scores.put("Carol", 92);
Map<String, Integer> immutableScores = Collections.unmodifiableMap(scores);
Map.of() – Java 9 Way (up to 10 entries)
import java.util.Map;
// Up to 10 key-value pairs – concise, one line
Map<String, Integer> scores = Map.of(
"Alice", 95,
"Bob", 87,
"Carol", 92
);
System.out.println(scores); // {Bob=87, Carol=92, Alice=95}
System.out.println(scores.get("Alice")); // 95
System.out.println(scores.size()); // 3
Map.of() is overloaded to accept up to 10 key-value pairs (20 arguments). For more than 10 entries, use Map.ofEntries().
Map.ofEntries() – For More Than 10 Entries
import java.util.Map;
import static java.util.Map.entry;
// Use Map.entry() to create individual entries
Map<String, Integer> cityPopulation = Map.ofEntries(
entry("Mumbai", 20_667_656),
entry("Delhi", 32_941_000),
entry("Bangalore", 12_476_000),
entry("Hyderabad", 10_534_000),
entry("Chennai", 7_088_000),
entry("Kolkata", 14_850_000),
entry("Pune", 6_629_000),
entry("Ahmedabad", 8_253_000),
entry("Jaipur", 3_073_000),
entry("Surat", 6_564_000),
entry("Lucknow", 3_382_000) // 11 entries – needs ofEntries()
);
System.out.println("Cities: " + cityPopulation.size());
System.out.println("Delhi population: " + cityPopulation.get("Delhi"));
Complete Example
package com.java9r;
import java.util.Map;
import static java.util.Map.entry;
/**
* Java 9 – Immutable Map factory methods demonstration.
*/
public class Java9ImmutableMapDemo {
public static void main(String[] args) {
// --- Map.of() ---
System.out.println("=== Map.of() ===");
var productPrices = Map.of(
"Laptop", 75000,
"Smartphone", 25000,
"Tablet", 35000,
"Monitor", 15000,
"Keyboard", 2500
);
productPrices.forEach((name, price) ->
System.out.printf(" %-12s : Rs. %,d%n", name, price));
System.out.println("\nContains 'Laptop': " + productPrices.containsKey("Laptop"));
System.out.println("Laptop price: Rs. " + String.format("%,d", productPrices.get("Laptop")));
// --- Map.ofEntries() ---
System.out.println("\n=== Map.ofEntries() ===");
var countryCapital = Map.ofEntries(
entry("India", "New Delhi"),
entry("USA", "Washington D.C."),
entry("UK", "London"),
entry("France", "Paris"),
entry("Germany", "Berlin"),
entry("Japan", "Tokyo"),
entry("China", "Beijing"),
entry("Australia", "Canberra"),
entry("Brazil", "Brasília"),
entry("Canada", "Ottawa"),
entry("South Africa", "Pretoria")
);
countryCapital.entrySet()
.stream()
.sorted(Map.Entry.comparingByKey())
.forEach(e ->
System.out.println(" " + e.getKey() + " -> " + e.getValue()));
// --- Attempting to modify throws UnsupportedOperationException ---
System.out.println("\n=== Immutability Check ===");
try {
productPrices.put("Mouse", 1500); // will throw
} catch (UnsupportedOperationException e) {
System.out.println("Cannot modify: " + e.getClass().getSimpleName());
}
try {
productPrices.remove("Laptop"); // will throw
} catch (UnsupportedOperationException e) {
System.out.println("Cannot remove: " + e.getClass().getSimpleName());
}
}
}
Expected Output
=== Map.of() ===
Laptop : Rs. 75,000
Smartphone : Rs. 25,000
Tablet : Rs. 35,000
Monitor : Rs. 15,000
Keyboard : Rs. 2,500
Contains 'Laptop': true
Laptop price: Rs. 75,000
=== Map.ofEntries() ===
Australia -> Canberra
Brazil -> Brasília
Canada -> Ottawa
China -> Beijing
France -> Paris
Germany -> Berlin
India -> New Delhi
Japan -> Tokyo
South Africa -> Pretoria
UK -> London
USA -> Washington D.C.
=== Immutability Check ===
Cannot modify: UnsupportedOperationException
Cannot remove: UnsupportedOperationException
Rules and Restrictions
There are four important rules to follow with Map.of() and Map.ofEntries():
- No null keys or values — both throw
NullPointerExceptionif you passnull - No duplicate keys — passing the same key twice throws
IllegalArgumentException - No modification — put, remove, or clear all throw
UnsupportedOperationException - No guaranteed order — the iteration order is not the insertion order
// This throws IllegalArgumentException – duplicate key
// Map.of("A", 1, "A", 2);
// This throws NullPointerException – null value
// Map.of("A", null);
// If you need a mutable copy of an immutable map:
var mutable = new java.util.HashMap<>(productPrices);
mutable.put("Mouse", 1500); // works fine
Summary
Java 9's Map.of() and Map.ofEntries() factory methods replace the verbose pre-Java 9 pattern of creating a HashMap and wrapping it with Collections.unmodifiableMap(). Use Map.of() for up to 10 entries and Map.ofEntries() with Map.entry() for larger maps. Remember: these maps are truly immutable — null keys/values and duplicate keys are not allowed, and the iteration order is unspecified. For a modifiable version, pass the immutable map to new HashMap<>().
Comments