Hello, in this tutorial we will see another JDK 9 feature i.e. creatingimmutable collections in Java. Java 9 brings the long awaited approach for creating small unmodifiable Collection instances using a concise one line code. As perJEP 269, new convenience factory methods will be included in JDK 9.
1. Introduction
Before Java 9, it was possible to create an immutable view of the collections but only with some utility methods e.g.Collections.unmodifiableCollection(Collection<? extends T> c). For example, let us create an immutable view of Collection in Java 8, with a one liner. It looks bad! Isn’t it?
Test.java
Map<String, String> immutableMap = Collections.unmodifiableMap(new HashMap<String, String>() {{ put("key1", "Value1"); put("key2", "Value2"); put("key3", "Value3");}});That’s too much code for a simple task and it should be possible to be done in a single expression. Java 9 brings now, something useful with the factory methods for creating immutable collections. Here are the examples of the factory methods:
Java Doc
// Empty Immutable CollectionsList emptyImmutableList = List.of();Set emptyImmutableSet = Set.of();Map emptyImmutableMap = Map.of();// Immutable CollectionsList immutableList = List.of("one", "two");Set immutableSet = Set.of("value1", "value2");Map<String, String> immutableMap = Map.of("key1", "Value1", "key2", "Value2", "key3", "Value3");2. Java 9 Immutable Collections Example
2.1 What are Collection Factory methods?
A collection factory method in Java is a static method that provides a simple way of initializing animmutableCollection<E>.
Beingimmutable,no elements can be added to,removed from, ormodified inside theCollection<E> after it is initialized. With Java 9, collection factory methods are provided for the following interfaces:List<E>,Set<E> andMap<K, V>
2.2 How are they implemented?
A new package-private utility class that resides in the JDK 9java.util.ImmutableCollections, provides multiple abstract classes that each represent a base for an immutableCollection<E>:AbstractImmutableList<E>,AbstractImmutableSet<E> andAbstractImmutableMap<K, V>.
These abstract classes are used to implement four concrete classes (except forAbstractImmutableMap<K, V> which implements three concrete classes) for eachCollection<E>:
- List<E>
List0<E>: An immutable implementation of an emptyList<E>List1<E>: An immutable implementation of aList<E>with one elementList2<E>: An immutable implementation of aList<E>with two elementsListN<E>:An immutable implementation of aList<E>with a variable amount of elements
- Set<E>
Set0<E>: An immutable implementation of an emptySet<E>Set1<E>: An immutable implementation of aSet<E>with one elementSet2<E>: An immutable implementation of aSet<E>with two elementsSetN<E>: An immutable implementation of aSet<E>with a variable amount of elements
- Map<K, V>
Map0<K, V>: An immutable implementation of an emptyMap<K, V>Map1<K, V>: An immutable implementation of aMap<K, V>with one key-value entryMapN<K, V>: An immutable implementation of aMap<K, V>with a variable amount of key-value entries
2.3 What do they improve?
Up until Java 9, there has been no simple universal method to initialize aCollection<E> with initial elements/key-value entries. Previously, developers were required to initialize them as follows (assuming the generic types E, K, and V have been replaced withInteger):
- List<Integer>
- The following method is arguably the simplest to initialize a
List<Integer>with initial elements, however the result is simply a view of aList<Integer>. We are unable to add to or remove from thisList<Integer>, but we are still able to modify existing elements by usingList#set. For E.g.:List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); - If we wanted our
List<Integer>to be entirely mutable, then we would have to pass it to the constructor of anArrayList<Integer>, for example:List<Integer> mutableList = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
- The following method is arguably the simplest to initialize a
- Set<Integer>
- A
Set<Integer>required more code to initialize with initial elements than aList<Integer>does, which can be seen as:Set<Integer> mutableSet = new HashSet<>(Arrays.asList(1, 2, 3, 4, 5));
- A
- Map<Integer, Integer>
- A
Map<Integer, Integer>is arguably the most complicated to initialize with initial key-value entries; however, there are multiple ways to go about it:- One method was to first initialize an empty
Map<Integer, Integer>and simply callMap#putto add key-value entries - Another method was to use an anonymous class with two curly braces, which would still require
Map#putto be called
- One method was to first initialize an empty
- A
2.4 What is the proper syntax to use?
For simplicity, we’re going to look at how to create List, Set, Map with Java 9 Factory Method for Collections.
2.4.1. List
To create a List, we use below static methods:
Java Doc
// for empty liststatic <E> List<E> of()// for list containing one elementstatic <E> List<E> of(E e1)// for list containing two elementstatic <E> List<E> of(E e1, E e2)// for list containing an arbitrary number of elementsstatic <E> List<E> of(E... elements)
For example:
Test.java
List<String> immutableList = List.of();immutableList = List.of("one", "two", "three", null);If we try to create list withnull element, ajava.lang.NullPointerException will be thrown:
Console Output
Exception in thread "main" java.lang.NullPointerExceptionat java.base/java.util.Objects.requireNonNull(Objects.java:221)at java.base/java.util.ImmutableCollections$ListN.(ImmutableCollections.java:233)at java.base/java.util.List.of(List.java:859)
Because the list created with static factory method is immutable, so if we try to add an element to list, it also throws anjava.lang.UnsupportedOperationException
Test.java
List<String> immutableList = List.of("one", "two", "three");immutableList.add("four");Console Output
Exception in thread "main" java.lang.UnsupportedOperationExceptionat java.base/java.util.ImmutableCollections.uoe(ImmutableCollections.java:70)at java.base/java.util.ImmutableCollections$AbstractImmutableList.add(ImmutableCollections.java:76)
Solution for problems above:
Test.java
List<String> mutableList = new ArrayList<String>(List.of("one", "two", "three"));mutableList.add("four");mutableList.add(null);Console Output
// Result: [one, two, three, four, null]
2.4.2. Set
To create a Set, we use below static methods:
Java Doc
// for empty Setstatic <E> Set<E> of()// for Set containing one elementstatic <E> Set<E> of(E e1)// for Set containing two elementstatic <E> Set<E> of(E e1, E e2)// for Set containing an arbitrary number of elementsstatic <E> Set<E> of(E... elements)
For example:
Test.java
Set<String> immutableSet = Set.of();immutableSet = Set.of("one", "two", "three", null);If we try to create set withnull element, ajava.lang.NullPointerException will be thrown:
Console Output
Exception in thread "main" java.lang.NullPointerExceptionat java.base/java.util.ImmutableCollections$SetN.probe(ImmutableCollections.java:520)at java.base/java.util.ImmutableCollections$SetN.(ImmutableCollections.java:460)at java.base/java.util.Set.of(Set.java:520)
Because the set created with static factory method is immutable, so if we try to add an element to set, it also throws anjava.lang.UnsupportedOperationException
Test.java
Set<String> immutableSet = Set.of("one", "two", "three");immutableSet.add("four");Console Output
Exception in thread "main" java.lang.UnsupportedOperationExceptionat java.base/java.util.ImmutableCollections.uoe(ImmutableCollections.java:70)at java.base/java.util.ImmutableCollections$AbstractImmutableSet.add(ImmutableCollections.java:280)
Solution for problems above:
Test.java
Set<String> mutableSet = new HashSet<String>(Set.of("one", "two", "three"));mutableSet.add("four");mutableSet.add(null);Console Output
// Result: [null, four, one, two, three]
2.4.3. Map
Map.of()
To create a Map, we use below static methods:
Java Doc
// for empty Mapstatic <K, V> Map<K, V> of()// for Map containing a single mappingstatic <K, V> Map<K, V> of(K k1, V v1)// for Map containing two mappingsstatic <K, V> Map<K, V> of(K k1, V v1, K k2, V v2)// for Map containing up to ten mappingsstatic <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)
For example:
Test.java
Map<Integer, String> immutableMap = Map.of(1, "one", 2, "two", 3, "three", 4, null );
If we try to create map withnull element, ajava.lang.NullPointerException will be thrown:
Console Output
Exception in thread "main" java.lang.NullPointerExceptionat java.base/java.util.Objects.requireNonNull(Objects.java:221)at java.base/java.util.ImmutableCollections$MapN.(ImmutableCollections.java:677)at java.base/java.util.Map.of(Map.java:1372)
Because the map created with static factory method is immutable, so if we try to put (key, value) pair to map, it also throws anjava.lang.UnsupportedOperationException
Test.java
Map<Integer, String> immutableMap = Map.of(1, "one", 2, "two", 3, "three");immutableMap.put(4, "four");
Console Output
Exception in thread "main" java.lang.UnsupportedOperationExceptionat java.base/java.util.ImmutableCollections.uoe(ImmutableCollections.java:70)at java.base/java.util.ImmutableCollections$AbstractImmutableMap.put(ImmutableCollections.java:557)
Solution for problems above:
Test.java
Map<Integer, String> mutableMap = new HashMap<Integer, String>(Map.of(1, "one", 2, "two", 3, "three"));mutableMap.put(4, "four");mutableMap.put(5, null);
Console Output
// Result:{1=one, 2=two, 3=three, 4=four, 5=null}Map.ofEntries()
If we want to create a Map with more than ten mappings, there is another way: UsingMap.ofEntries() method.
Java Doc
static <K, V> Map<K, V> ofEntries(Entry<? extends K, ? extends V>... entries)
To use that method, we use a method for boxing keys and values, suitable for static import:
Java Doc
static <K, V> Entry<K, V> entry(K k, V v)
So, this is way to use them:
Test.java
Map<Integer, String> newImmutableMap = Map.ofEntries(Map.entry(1, "one"), Map.entry(2, "two"), Map.entry(3, "three"));
2.5 Can I use collection factory methods to create mutable objects?
TheCollection<E> created by collection factory methods are inherently immutable, however we are able to pass them to a constructor of an implementation of theCollection<E> to produce a mutable version i.e.
- List<Integer>
List<Integer> mutableList = new ArrayList<>(List.of(1, 2, 3, 4, 5));
- Set<Integer>
Set<Integer> mutableSet = new HashSet<>(Set.of(1, 2, 3, 4, 5));
- Map<Integer, Integer>
Map<Integer, Integer> mutableMap = new HashMap<>(Map.of(1, 2, 3, 4));
3. Pitfalls of Java’s Immutable Collections
The danger of Java’s implementation is that because there is no interface specifically for immutable collections, those immutableSet andMap collections still have the mutable methodsadd/put and remove which will throw anUnsupportedOperationException if called.
Blankly looking atof, it isn’t obvious that the returned collection is immutable. AHashSet would be a reasonable guess since it is by far the most widely used Java set. Java’s ComparableEnumSet.of(...) returns a mutable set. More than a few runtime exceptions are going to be thrown due toof ambiguous return type.
4. Conclusion
The main goal of this article is to discuss the new collection factory methods in Java 9. Of all the new features added to Java 9, the factory methodof is one of the more useful in day-to-day programming but it needs to be used with caution.
5. Download the Eclipse Project
This was an example of Java 9 Immutable Collections. Run the code and the result will be printed in the console window.
You can download the full source code of this example here:Java9 Immutable Collections

Thank you!
We will contact you soon.



