How to Create Immutable Map in Java?

Learn to create an immutable or unmodifiable Map using the factory methods added in Java 9 and other versions (Java 8 to Java 21) with examples.

Java Collections

Added in Java 9, the Map.of, Map.ofEntries and Map.copyOf methods (also called factory methods) are very convenient for quickly and effortlessly creating and populating unmodifiable/immutable Map objects.

In this Java tutorial, we will learn to create immutable/unmodifiable Map instances with/without the help of these factory methods.

1. Creating Immutable Map since Java 9

1.1. Create Immutable Map with Upto 10 Key-Value Pairs

Starting with JDK 9, we can rely on the factory method Map.of() to create an immutable Map (with a maximum of 10 key-value pairs) [JEP-269]. The Map.of() is an overloaded method that accepts 0 to 10 key-value pairs.

Map<String, String> imap = Map.of(
  "key 1", "value 1",
  "key 2", "value 2",
  "key 3", "value 3"
);

Maps created via Map.of() don’t allow null keys or values. Such attempts will end up in a NullPointerException.

Map<String, String> imap = Map.of("key 1", null);

The program error:

Exception in thread "main" java.lang.NullPointerException
	at java.base/java.util.Objects.requireNonNull(Objects.java:233)
	at java.base/java.util.ImmutableCollections$MapN.<init>(ImmutableCollections.java:1193)
	at java.base/java.util.Map.of(Map.java:1407)

1.2. Create Immutable Map Containing More Than 10 Key-Value Pairs

When we have to add more than 10 key-value pairs in the immutable Map, we can rely on Map.ofEntries() factory method. The ofEntries() method accepts a varargs of type Entry so we can pass any number of key-value pairs.

Map<String, String> imap = Map.ofEntries(
    entry("key 1", "value 1"),
    entry("key 2", "value 2"),
    entry("key 3", "value 3"),
    entry("key 4", "value 4"),
    entry("key 5", "value 5"),
    entry("key 6", "value 6"),
    entry("key 7", "value 7"),
    entry("key 8", "value 8"),
    entry("key 9", "value 9"),
    entry("key 10", "value 10"),
    entry("key 11", "value 11"),
    entry("key 12", "value 12")
);

Note that null keys or values are not allowed in ofEntries() method as well. So, please filter out any null key or value before calling the Map.entry() method.

1.3. Create Immutable Map From Mutable Map

Another factory method Map.copyOf() was added in Java 10 which can help you in creating immutable Maps from a given mutable map. Again, the mutable map must not contain any null keys or values.

Map<String, String> map = new HashMap<>();
map.put("key 1", "value 1");
map.put("key 2", "value 2");
map.put("key 3", "value 3");

Map<String, String> imap = Map.copyOf(map);

If the given Map is subsequently modified, the returned Map will not reflect such modifications. We can see in the following example that when the original mutable map was modified, it didn’t affect the immutable map created with copyOf() method.

Map<String, String> map = new HashMap<>();
map.put("key 1", "value 1");
map.put("key 2", "value 2");
map.put("key 3", "value 3");

Map<String, String> imap = Map.copyOf(map);
//modify the original map
map.put("key 4", "value 4");

System.out.println(map);  // {key 4=value 4, key 3=value 3, key 2=value 2, key 1=value 1}
System.out.println(imap); // {key 3=value 3, key 1=value 1, key 2=value 2}

1.4. Collecting Key-Value Pairs from Stream into Immutable Map

Java Streams are great for pipeline methods and performing several actions on a collection of elements in a sequence. After we have processed the Stream elements, we can collect them into an immutable Map as follows:

Map<String, String> imap = Stream.of(
            entry("key 1", "value 1"),
            entry("key 2", "value 2"),
            entry("key 3", "value 3"))
        .collect(toUnmodifiableMap(e->e.getKey(), e->e.getValue()));

2. Creating Immutable Map in Java 8

If your application runs on Java 8 then the first recommendation is to upgrade the JDK to the latest version. There have been so many performance and API improvements and you will greatly benefit from them.

In Java 8, the easiest method for creating an unmodifiable Map is using the Collections.unmodifiableMap() method. This is super useful because it allows us to create an unmodifiable map from a modifiable one.

Map<Integer, String> map = new HashMap<>();
map.put("key 1", "value 1");
map.put("key 2", "value 2");
map.put("key 3", "value 3");
...
...

Map<Integer, String> imap = Collections.unmodifiableMap(map);
//immutableMap.put("key2", "value2"); // throws java.lang.UnsupportedOperationException

If you are collecting the key-value pairs from a Stream then Collectors.toMap() can be used in addition to Collections::unmodifiableMap. In the following example, we have a Stream of java.util.Map.entry and we are collecting them into an unmodifiable map.

Map<Integer, String> imap = Stream.of(
		  entry("key 1", "value 1"),
		  entry("key 2", "value 2"),
		  entry("key 3", "value 3"))
  .collect(collectingAndThen(toMap(e -> e.getKey(), e -> e.getValue()), Collections::unmodifiableMap));

3. Summary

In this quick Java tutorial, we learned to create an immutable or unmodifiable Map using the factory method added in Java 9 and later. We also learned to create immutable maps using the Java 8 APIs.

Happy Learning !!

Weekly Newsletter

Stay Up-to-Date with Our Weekly Updates. Right into Your Inbox.

Comments

Subscribe
Notify of
0 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.