Java 9 – How to create immutable collections using List.of, Set.of, Map.of, Map.ofEntries methods with examples

Introduction
This tutorial explains how to use Java 9 Collections’ new factory methods for creating immutable collection instances with examples to show their usage. There are 4 factory methods viz. List.of(), Set.of(), Map.of() and Map.ofEntries(). To begin with let us look at when to use the new Collection Factory methods.

When and why to use the new factory methods
Until Java 8, if one needed an immutable instance of a List, Set or Map, i.e. a collection instance which can’t be modified once it has been created, then it took multiple lines of code. First an instance of the collection needed to be created using its constructor, then elements need to be added to the instance one at a time, and finally that collection instance was made unmodifiable using a method provided in Collections API for the same.
For example, to create a 2 member list until Java 8 required the following lines of code –

  List oldStyleList = new ArrayList<>();
  oldStyleList.add(2);
  oldStyleList.add(10);
  oldStyleList = Collections.unmodifiableList(oldStyleList);

The above process is verbose and time consuming. In addition, a specific sub-type of the collection(such as ArrayList for List or HashSet for Set) needs to be selected as the base types(List, Set, Map) are interfaces.

In Java 9, creating an immutable collection is now much simpler with the new factory method of() that has been added to the 3 collection interfaces – List, Set, Map. These factory methods take zero or more elements as inputs and construct an immutable collection instance.
The same 2 member list created above can be created in Java 9 like this

 List newImmutableList = List.of(2,10);
Let us now take a detailed look at the new factory methods and how they can be used to define immutable List, Set and Map instances.

List.of() method
The List.of() method has 2 variants –

  1. First overloaded variant accepts 0(to create an empty list) to 10 elements of a type(say E) passed as input, and it returns an immutable List instance of type E, or List.

    Signature of List.of() method with 2 input parameters would look like this –

    static List List.of(E e1,E e2)

    Similarly, a method with 3 input parameters would look like this –

    static List List.of(E e1, E e2, E e3)

    And so on… up to 10 input parameters.

  2. The second overloaded variant of List.of() method comes in handy if you have more than 10 elements which need to be part of the immutable list, or you have an array all the elements of which need to be part of the immutable list. This method accepts variable number of arguments specified using varargs.

    It is defined with the signature –

    static List List.of(E... elements)

It is important to note at this point that if any of the list modification methods(such as List.add(), List.remove(), etc) are used on the immutable lists created using the List.of() method then an instance of UnsupportedOperationException is thrown. This is a Runtime ExceptionClick to Read tutorial explaining Exception Hierarchy in Java.

Let us now see a Java 9 code example showing usage of List.of() method variants.

Java 9 code showing List.of() method usage
package com.javabrahman.jdk9;
import java.util.ArrayList;
import java.util.List;
public class FactoryMethods {
    public static void main(String args[]){
        //List.of() variant#1
        List<Integer> newImmutableList = List.of(2,10);
        System.out.println("Elements in newImmutableList:" + newImmutableList);
      
        //List.of() variant#2
        Integer[] integerArray = {1,2,3,4};
        List<Integer> listFromArray = List.of(integerArray);
        System.out.println("Elements in listFromArray:" + listFromArray);
    }
}
 OUTPUT of the above code
Elements in newImmutableList: [2, 10]
Elements in listFromArray: [1, 2, 3, 4]
Explanation of the code

  • FactoryMethods class’ main() method first defines an immutable List named newImmutableList using List.of() method with two Integer values 2 and 10 passed as input.
  • Contents of newImmutableList are then printed correctly as [2,10].
  • Next, an Integer array is defined, named integerArray, and initialized with the values 1,2,3,4.
  • integerArray is then passed as input to List.of() method to get an instance of an immutable List which is assigned to the variable listFromArray.
  • Contents of listFromArray are then printed correctly as [1,2,3,4].

Set.of() method
Similar to List.of() method above, Set.of() method also has 2 variants –

  1. First overloaded variant accepts 0(to create an empty set) to 10 elements of a type(say E) passed as input, and it returns an immutable Set instance of type E, or Set.

    For example, signature of Set.of() method with 2 input parameters would look like this –

    static Set of(E e1, E e2)
  2. The second overloaded variant of Set.of() method comes in handy if you have more than 10 elements which need to be part of the immutable set, or you have an array all the elements of which need to be part of the immutable Set. This method accepts variable number of arguments specified using varargs.

    It is defined with the signature –

    static Set of(E... elements)

It is important to note that if the array has multiple elements of same value then the immutable Set instance created contains the duplicate value only once. This is due to the intrinsic property of a Set which allows it to hold only unique values.

Similar to immutable lists, using Set modification methods such as Set.add(), Set.remove(), etc) on the immutable Set throws the Runtime Exception UnsupportedOperationException.

Let us now see a Java 9 code example showing usage of Set.of() method variants.

Java 9 code showing Set.of() method usage
package com.javabrahman.jdk9;
import java.util.HashSet;
import java.util.Set;
public class FactoryMethods {
    public static void main(String args[]){
        //Set.of() variant#1
        Set<Integer> newImmutableSet = Set.of(25,40,75);
        System.out.println("Elements in newImmutableSet:" + newImmutableSet);

        //Set.of() variant#2
        Integer[] intArray = {1,2,3,4};
        Set<Integer> setFromArray = Set.of(intArray);
        System.out.println("Elements in setFromArray:" + setFromArray);
}
}
 OUTPUT of the above code
Elements in newImmutableSet: [75, 40, 25]
Elements in setFromArray: [4, 2, 3, 1]
Explanation of the code

  • FactoryMethods class’ main() method first defines an immutable Set named newImmutableSet using Set.of() method with two Integer values 25, 40 and 75 passed as input.
  • Contents of newImmutableSet are then printed correctly as [25,40,75].
  • Next, an Integer array is defined, named integerArray, and initialized with the values 1,2,3,4.
  • integerArray is then passed as input to Set.of() method to get an instance of an immutable Set which is assigned to the variable setFromArray.
  • Contents of setFromArray are then printed correctly as [1,2,3,4].

Map.of() method
Unlike List.of() and Set.of() methods, Map.of() method only has 1 variant which accepts 0(to create an empty map) to 10 key-value pairs of a type(say K,V) passed as input, and it returns an immutable Map instance of type K,V, or Map.

For example, signature of Map.of() method with 2 key-value pairs would look like this –

static Map of(K k1, V v1, K k2, V v2)

It is important to note at this point that if any of the Map modification methods(such as Map.put(), Map.remove(), etc) are used on the immutable maps created using the Map.of() method then an instance of UnsupportedOperationException is thrown. This is a Runtime ExceptionClick to Read tutorial explaining Exception Hierarchy in Java.

Let us now see a Java 9 code example showing usage of Map.of() method.

Java 9 code showing Map.of() method usage
package com.javabrahman.jdk9;
import java.util.Map;
public class FactoryMethods {
    public static void main(String args[]){

        Map<String,Integer> newImmutableMap = Map.of("key1", 1, "key2", 2);
        System.out.println("Elements in newImmutableMap:" + newImmutableMap);

    }
}
 OUTPUT of the above code
Elements in newImmutableMap: {key1 = 1, key2 = 2}
Explanation of the code

  • FactoryMethods class’ main() method first defines an immutable Map named newImmutableMap using Map.of() method with two key-value pairs passed as input – ("key1",1) and ("key2",2).
  • Contents of newImmutableMap are then printed correctly as {key1=1, key2=2}.

Map.ofEntries() and Map.entry() method
Map.ofEntries() is slightly different from the collection factory methods we saw above. It does use varargs to support a variable number of map entries as input. However, instead of directly taking key-value pair values as input, it instead accepts unmodifiable map entries created using the new static method Map.entry().

Map.entry() method is defined with the following signature –

static Entry entry(K k, V v)

Where,
k and v are the key and value stored in the map entry
K and V are the key and value types
Output is an unmodifiable Map.Entry instance

Map.ofEntries() accepts a variable number of Map.Entry instances as input and returns an unmodifiable Map instance containing the entries passed to it. It is defined with the following signature –

static Map ofEntries(Entry... entries)

Where,
entries is a varargs parameter of type Map.Entry.
K and V are the key and value types of each entry.
Output is an unmodifiable Map instance containing the unmodifiable entries passed as input to it.

It is for the purpose of creating unmodifiable Map.Entry instances passed as input to Map.ofEntries() method that the new Map.entry() method we saw earlier has been provided.

Let us now take a look at a code example to see an example of how Map.ofEntries() and Map.entry() methods work together –

Java 9 code showing Map.ofEntries() and Map.entry() methods usage
package com.javabrahman.jdk9;
import java.util.Map;
public class FactoryMethods {
    public static void main(String args[]){
        Map<String,Integer> mapFromEntries = Map.ofEntries(Map.entry("key10", 10), Map.entry("key20",20));
        System.out.println("Elements in mapFromEntries: " + mapFromEntries);
    }
}
 OUTPUT of the above code
Elements in mapFromEntries: {key10=10, key20=20}
Explanation of the code

  • FactoryMethods class’ main() method first defines an immutable Map named mapFromEntries to which two instances of Map.Entry are passed as input.
  • Map.Entry instances are in turn created using Map.entry() method. So, Map.entry("key10", 10) defines an unmodifiable Map.Entry instance with key as "key10" and value as 10. Likewise for Map.entry("key20", 20).
  • Contents of mapFromEntries are then printed correctly as {{key10=10, key20=20}.

Summary
In this tutorial we understood how to create immutable Set, List and Map collection instances using List.of(), Set.of(), Map.of() and Map.ofEntries() factory methods in Java 9 Collections and saw code examples of their usage. We also looked at the new static Map.entry() method which has been provided to create unmodifiable entries for Map.ofEntries() method.

 

Digiprove sealCopyright © 2014-2018 JavaBrahman.com, all rights reserved.