HomeCore JavaCollections Factory Methods in java 9

Collections Factory Methods in java 9

Convenience Factory Methods for Collections in JDK 9 :

This article can be consider as continuation article for the Creating immutable collections before JDK 9. In this article we explained how JDK 9 solves the flaws of creating simple immutable collections. See JEP 269: Convenience Factory Methods for Collections

JDK 9 introduced of() static factory method in ListSetMap interfaces, by using the of() static factory method of ListSetMap interfaces and ofEntries(), and entry() static factory methods of Map interface its possible to create true immutable collections very easy.

List.of() :

JDK 9 added an overloaded of() static factory method to the List interface. It provides a simple and way to create unmodifiable lists. Here are all the different versions of the of() method:

static <E> List<E>  of() - Returns an immutable list containing 0 elements
static <E> List<E>  of(E e1) - Returns an immutable list containing 1 elements
static <E> List<E>  of(E e1, E e2)
static <E> List<E>  of(E e1, E e2, E e3)
static <E> List<E>  of(E e1, E e2, E e3, E e4)
static <E> List<E>  of(E e1, E e2, E e3, E e4, E e5)
static <E> List<E>  of(E e1, E e2, E e3, E e4, E e5, E e6)
static <E> List<E>  of(E e1, E e2, E e3, E e4, E e5, E e6, E e7)
static <E> List<E>  of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8)
static <E> List<E>  of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9)
static <E> List<E>  of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10)
 
//varargs for arbitary elements
static <E> List<E>  of(E... elements)

The List instances created by these methods have the following characteristics :

  1.  They are structurally immutable. Elements cannot be added, removed, or replaced. If we try to do so method will always cause UnsupportedOperationException to be thrown.
  2. They disallow null elements. Attempts to create them with null elements result in NullPointerException.
  3. The order of elements in the list is the same as the order of the provided arguments.
  4. They are serializable if all elements are serializable.
  5. The instances created by factory methods are value based. This means that factories are free to create a new instance or return an existing instance.

Immutable List example :

public class ImmutableListTest {
 
        public static void main(String[] args) {
            
            // Creating empty list
            List<String> emptyList = List.of();
            
            //Creating immutable list
            List<String> immutableList = List.of("Peter", "Philip");
            
            System.out.println("emptyList = " + emptyList);
            System.out.println("Immutable List = " + immutableList);
            
            //Try using null
            try {
    
                List>String< list = List.of("Peter",null, "Philip");
                
            } catch (NullPointerException e) {
                System.out.println("nulls are not allowed in List.of()");
            }
            
            // Try adding an element to immutable list
            try {
                
                immutableList.add("Gerhard");
                
            } catch (UnsupportedOperationException e) {
                System.out.println("Cannot add an element to the immutable List");
            }
            
            // Try removing an element from immutable List
            try {
                
                immutableList.remove(1);
            } catch (UnsupportedOperationException e) {
                System.out.println("Cannot remove an element from immutable List");
            }
        }
}

Output :

emptyList = []
Immutable List = [Peter, Philip]
nulls are not allowed in List.of()
Cannot add an element to the immutable List
Cannot remove an element from immutable List

Set.of() :

JDK 9 added an overloaded of() static factory method to the Set interface. It provides a simple and way to create unmodifiable sets. Here are all the different versions of the of() method:

static <E> Set<E>   of() - Returns an immutable set containing 0 elements
static <E> Set<E>   of(E e1) - Returns an immutable set containing 1 elements
static <E> Set<E>   of(E e1, E e2)
static <E> Set<E>   of(E e1, E e2, E e3)
static <E> Set<E>   of(E e1, E e2, E e3, E e4)
static <E> Set<E>   of(E e1, E e2, E e3, E e4, E e5)
static <E> Set<E>   of(E e1, E e2, E e3, E e4, E e5, E e6)
static <E> Set<E>   of(E e1, E e2, E e3, E e4, E e5, E e6, E e7)
static <E> Set<E>   of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8)
static <E> Set<E>   of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9)
static <E> Set<E>   of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10)
 
//varargs
static <E> Set<E>   of(E... elements)

The Set instances created by these methods have the following characteristics :

  1.  They are structurally immutable. Elements cannot be added, removed, or replaced. If we try to do so method will always cause UnsupportedOperationException to be thrown.
  2. They disallow null elements. Attempts to create them with null elements result in NullPointerException.
  3. They reject duplicate elements at creation time. If you try to add existing set created by factory method throws IllegalArgumentException.
  4. The iteration order of set elements is unspecified.
  5. They are serializable if all elements are serializable.
  6. The instances created by factory methods are value based. This means that factories are free to create a new instance or return an existing instance.

Immutable Set example :

public class ImmutableSetTest {
 
        public static void main(String[] args) {
            
            // Creating empty Set
            Set<String> emptySet = Set.of();
            
            //Creating immutable Set
            Set<String> immutableSet = Set.of("Peter", "Philip");
            
            System.out.println("emptySet = " + emptySet);
            System.out.println("Immutable Set = " + immutableSet);
            
            //Try using null
            try {
    
              Set<String> set = Set.of("Peter",null, "Philip");
                
            } catch (NullPointerException e) {
                System.out.println("nulls are not allowed in Set.of()");
            }
            
            // Try adding an element to immutable Set
            try {
                
                immutableSet.add("Gerhard");
                
            } catch (UnsupportedOperationException e) {
                System.out.println("Cannot add an element to the immutable Set");
            }
            
            // Try removing an element from immutable Set
            try {
                
                immutableSet.remove(1);
            } catch (UnsupportedOperationException e) {
                System.out.println("Cannot remove an element from immutable Set");
            }
        }
}

Output :

emptySet = []
Immutable Set = [Peter, Philip]
nulls are not allowed in Set.of()
Cannot add an element to the immutable Set
Cannot remove an element from immutable Set

Map.of() :

JDK 9 added an overloaded of() static factory method to the Map interface. It provides a simple and way to create unmodifiable key values. Here are all the different versions of the of() method.

static lt;K,Vgt; Maplt;K,Vgt; of() - Returns an immutable map containing 0 key vale
static lt;K,Vgt; Maplt;K,Vgt; of(K k1, V v1) - Returns an immutable map containing 1 key value
static lt;K,Vgt; Maplt;K,Vgt; of(K k1, V v1, K k2, V v2)
static lt;K,Vgt; Maplt;K,Vgt; of(K k1, V v1, K k2, V v2, K k3, V v3)
static lt;K,Vgt; Maplt;K,Vgt; of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4)
static lt;K,Vgt; Maplt;K,Vgt; of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5)
static lt;K,Vgt; Maplt;K,Vgt; 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)
static lt;K,Vgt; Maplt;K,Vgt; 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)
static lt;K,Vgt; Maplt;K,Vgt; 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)
static lt;K,Vgt; Maplt;K,Vgt; 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)
static lt;K,Vgt; Maplt;K,Vgt; 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)

The Map instances created by these methods have the following characteristics :

  1.  They are structurally immutable. Elements cannot be added, removed, or replaced. If we try to do so method will always cause UnsupportedOperationException to be thrown.
  2. They disallow null keys. Attempts to create key with null elements result in NullPointerException.
  3. They reject duplicate keys at creation time. If you try to add duplicate key to the existing map created by factory method throws IllegalArgumentException.
  4. The iteration order of map elements is unspecified.
  5. They are serializable if all keys are serializable.
  6. The instances created by factory methods are value based. This means that factories are free to create a new instance or return an existing instance. And can not predict implementation classes that are returned by factory methods.

Immutable Map example :

public class ImmutableMapTest {
 
    public static void main(String[] args) {
 
        // Creating immutable Empty map
        Map<Integer, String> emptyMap = Map.of();
        
        //Creating immutable map
        Map<Integer, String> immutableMap = Map.of(1, "Peter", 2, "Gerhard");
 
        System.out.println("emptyMap = " + emptyMap);
        System.out.println("Immutable Map = " + immutableMap);
        
        // Adding a null value
        try {
            Map<Integer, String> map = Map.of(1, "Peter", 2, null);
        } catch (NullPointerException e) {
            System.out.println("Nulls not allowed in Map.of().");
        }
        
        // Adding new entry
        try {
            immutableMap.put(3, "Philip");
        } catch (UnsupportedOperationException e) {
            System.out.println("Cannot add a new entry to immutable Map.");
        }
        
        // Adding Duplicate key/entry
        try {
    
            Map<Integer, String> map = Map.of(1, "Peter", 2, "Gerhard", 1, "Philip");
        } catch (IllegalArgumentException e) {
            System.out.println(e.getMessage() + " Can not be added to the immutable list");
        }
        
        // removing an entry from existing immutable map
        try {
            immutableMap.remove(1);
        } catch (UnsupportedOperationException e) {
            System.out.println("Cannot remove entry from immutable map");
        }
    }
}

Output :

emptyMap = {}
Immutable Map = {2=Gerhard, 1=Peter}
Nulls not allowed in Map.of().
Cannot add a new entry to immutable Map.
duplicate key: 1 Can not be added to the immutable list
Cannot remove entry from immutable map

Map.ofEntries() :

Similarly to List and Set, the of(…) method is overloaded to have 0 to 10 key-value pairs. If more than 10 arguments List and Set interfaces has var-arg methods, in the case of Map, there is no possibility to add var-args for key values, for this Map also has different method called ofEntries(). In below example entry is a static method of Map interface and its static import in example.

import java.util.Map;
import static java.util.Map.entry;
 
public class ImmutableMapTest2 {
 
    public static void main(String[] args) {
 
        Map<Integer,String> map = Map.ofEntries(
                entry(1, "Peter"),
                entry(2, "Gerhad"),
                entry(3, "Philip")
                );
 
        System.out.println(map);
    }
 
}

Also see related articles :
Creating immutable collections before JDK 9

LEAVE A REPLY

Please enter your comment!
Please enter your name here