How to create immutabe Map in Java


Hello Friends,

In this tutorial, we will see how we can create an immutable Map in Java.


- What does it mean by immutable class or object?
- What is an Immutable Map?
- How to create an immutable Map in java?


What does it mean by immutable class or object?

An immutable class or object is a class or object whose state does not change once it is created. For example String class in Java is immutable, such that if we try to make changes in our String object ,it will create a new String object but state of current object will not change. So if we instantiate an immutable class, we can not change the state of that instance, once it is created.

What is an Immutable Map?

So considering the above definition of immutable, an immutable map is a map in which we can not insert, update or delete elements once it is created. This kind of Map will usually be required to have content which is not expected to be changed like country and it's currency.

How to create an immutable Map in java?

There are various ways in which we can create an Immutable Map.

- Using Collections.unmodifiableMap() 
- Using Map.of()
- Using Map.ofEntries()
- Using Map.copyOf()

Using Collections.unmodifiableMap() 

Example 1

When we use Collections.unmodifiableMap(originalMap),it creates a view over our original map, such that we can not add, delete or update on this view and if we try ,we get UnSupportedOperation exception, but we can just view the data which is there in the original map.

We can still update the original map and as we change original Map ,changes will be reflected in the view as well. so this does not in true sense creates immutable map.However we can still create immutable map using Collections.unmodifiableMap(). For that check second example.
    Map<String, Integer> originalMap1 = new HashMap<String, Integer>(); 
    originalMap1.put("a", 1); 
    originalMap1.put("b", 2);
    originalMap1.put("c", 3);
    Map<String, Integer> unmodifiableMap1 = Collections.unmodifiableMap(originalMap1);
    //unmodifiableMap1.put("d", 4);
    System.out.println("Size of originalMap1 before adding new data:"+originalMap1.size());
    System.out.println("Size of unmodifiableMap1 before adding new data:"+ unmodifiableMap1.size());
    originalMap1.put("e", 5);
    System.out.println("Size of originalMap1 after adding new data:"+originalMap1.size());
    System.out.println("Size of unmodifiableMap1 after adding new data:"+unmodifiableMap1.size());
 

Example 2

Here instead of passing reference to the original map, we create a new instance of HashMap, passing it original hashMap and then pass this new instance of HashMap to Collecitons.unmodifiableMap() method.The "unmodifiableMap2" that we get here is immutable such that even if you make changes in the original hashmap, it will not reflect in the unmodifiableMap2 instance.
        Map<String, Integer> originalMap2 = new HashMap<String, Integer>();
        originalMap2.put("a", 1);
        originalMap2.put("b", 2);
        originalMap2.put("c", 3);
        Map<String, Integer> unmodifiableMap2 = Collections.unmodifiableMap(new HashMap<String, Integer>(originalMap2));
        //unmodifiableMap2.put("d", 4);
        System.out.println("Size of originalMap2 before adding new data:" + originalMap2.size());
        System.out.println("Size of unmodifiableMap2 before adding new data:" + unmodifiableMap2.size());
        originalMap2.put("e", 5);
        System.out.println("Size of originalMap2 after adding new data:" + originalMap2.size());
        System.out.println("Size of unmodifiableMap2 after adding new data:" + unmodifiableMap2.size());

   

Using Map.of()

Map.of() was introduced in Java 9.Following example is self explanatory. This method should be used if we have less than equal to 10 key value pairs, because if we see the overloads of Of() method, there are maximum 10 key value pairs allowed in the overload of Of() method.
        static <K, V> Map<K, V> of()
        static <K, V> Map<K, V> of(K k1, V v1)
        static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2)
        .        
        .                                                                               .
        static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10)

Example
    
        Map<String, Integer> immutableMap1 = Map.of("a", 1, "b", 2, "c", 3);
        //immutableMap1.put("d", 4);  //Will throw UnsupportedOperaironException
        System.out.println("Size of immutableMap1:" + immutableMap1.size());
   

Using Map.ofEntries()

Map.ofEntries() was also introduced in Java 9.We can use this method of creating immutable map when we have more than 10 key value pairs.

Signature of this method is as below :
static <K, V> Map<K, V> ofEntries(Entry<? extends K, ? extends V>... entries)
Example
Map<String, Integer> immutableMap2 = Map.ofEntries(
                                                    entry("a", 1),
                                                    entry("b", 2),
                                                    entry("c", 3));
//immutableMap2.put("d", 4);
System.out.println("Size of immutableMap2 :" + immutableMap2.size());
     

Using Map.copyOf()

Map.copyOf() was introduced in Java 10.

Signature of this method is as below :
static <K, V> Map<K, V> copyOf(Map<? extends K, ? extends V> map) 

Example
Map<String, Integer> originalMap5 = new HashMap<String, Integer>();
originalMap5.put("a", 1);
originalMap5.put("b", 2);
originalMap5.put("c", 3);
Map<String, Integer> immutableMap3 = Map.copyOf(originalMap5);

//immutableMap3.put("d", 4);
System.out.println("Size of originalMap5 before adding new data:" + originalMap5.size());
originalMap5.put("e", 5);
System.out.println("Size of originalMap5 after adding new data:" + originalMap5.size());
System.out.println("Size of immutableMap3 after adding new data:" + immutableMap3.size());
     

Complete code with all above examples

package com.blogspot.javasolutionsguide.immutable_map_java_example;

import static java.util.Map.entry;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * ImmutableMapTest.
 */
public class ImmutableMapTest {
    public static void main(String[] args) {

        // //Example 1
        Map<String, Integer> originalMap1 = new HashMap<String, Integer>();
        originalMap1.put("a", 1);
        originalMap1.put("b", 2);
        originalMap1.put("c", 3);
        Map<String, Integer> unmodifiableMap1 = Collections.unmodifiableMap(originalMap1);
        //unmodifiableMap1.put("d", 4);
        System.out.println("Size of originalMap1 before adding new data:" + originalMap1.size());
        originalMap1.put("e", 5);
        System.out.println("Size of originalMap1 after adding new data:" + originalMap1.size());
        System.out.println("Size of unmodifiableMap1 after adding new data:" + unmodifiableMap1.size());


        //Example 2
        Map<String, Integer> originalMap2 = new HashMap<String, Integer>();
        originalMap2.put("a", 1);
        originalMap2.put("b", 2);
        originalMap2.put("c", 3);
        Map<String, Integer> unmodifiableMap2 = Collections.unmodifiableMap(new HashMap<String, Integer>(originalMap2));
        //unmodifiableMap2.put("d", 4);
        System.out.println("Size of originalMap2 before adding new data:" + originalMap2.size());
        originalMap2.put("e", 5);
        System.out.println("Size of originalMap2 after adding new data:" + originalMap2.size());
        System.out.println("Size of unmodifiableMap2 after adding new data:" + unmodifiableMap2.size());

        //Example 3
        Map<String, Integer> immutableMap1 = Map.of("a", 1, "b", 2, "c", 3);
        //immutableMap1.put("d", 4);     //Will throw UnsupportedOperaironException
        System.out.println("Size of immutableMap1:" + immutableMap1.size());

        //Example 4
        Map<String, Integer> immutableMap2 = Map.ofEntries(
                entry("a", 1),
                entry("b", 2),
                entry("c", 3));
        //immutableMap2.put("d", 4);
        System.out.println("Size of immutableMap2 :" + immutableMap2.size());

        //Example 5
        Map<String, Integer> originalMap5 = new HashMap<String, Integer>();
        originalMap5.put("a", 1);
        originalMap5.put("b", 2);
        originalMap5.put("c", 3);
        Map<String, Integer> immutableMap3 = Map.copyOf(originalMap5);
        //immutableMap3.put("d", 4);
        System.out.println("Size of originalMap5 before adding new data:" + originalMap5.size());
        originalMap5.put("e", 5);
        System.out.println("Size of originalMap5 after adding new data:" + originalMap5.size());
        System.out.println("Size of immutableMap3 after adding new data:" + immutableMap3.size());

    }
}

Summary :

So ,in this tutorial, we saw how we can create immutable map in Java. This is really useful when we know that content of our map is not going to change in future. We saw how JDK has various methods to create immutable maps.

Thanks for reading. Subscribe to our blog for more such interesting posts.