CoreJava Java9

Java 9 – Factory Methods for Immutable Map: Map.of() and Map.ofEntries()

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():

  1. No null keys or values — both throw NullPointerException if you pass null
  2. No duplicate keys — passing the same key twice throws IllegalArgumentException
  3. No modification — put, remove, or clear all throw UnsupportedOperationException
  4. 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<>().

Topics: CoreJava Java9
← Newer Post Older Post →

Comments

https://www.blogger.com/comment/frame/6690124484600543990?po=9027245582818548341&hl=en&saa=85391&origin=https://www.java9r.com