This quick tutorial is going to illustrate how to create immutable Lists in Java 9 by using convenience static factory methods on the List interface, which were added in JDK 9.
1. Prerequisites
Because will get through some Java 9 examples in this tutorial, below are prerequisites:
- Java 9 installed in our environment
- Java 9 supported IDE
- Build Tools such as Gradle or Maven (optional to run the tests)
You can quickly get a simple Java 9 project set up by following Java 9 Example With Maven And JUnit 5 or Set Up Eclipse, IntelliJ And NetBeans For Java 9.
The sample sources presented in this tutorial is available on my Github project. It’s a Maven-based project, so it’s easy to run or imported in any IDE.
2. Syntax To Create Immutable Lists In Java 9
Let’s take a quick look at the syntax of the convenience static factory methods to create immutable Lists in Java 9:
1 2 3 4 |
List.of() List.of(e1) List.of(e1, e2) // fixed-argument form overloads up to 10 elements List.of(elements...) // varargs form supports an arbitrary number of elements or an array |
And let’s see an example which we create a list of fruits in Java 9 using the above syntax:
1 |
List<String> fruits = List.of("Star apple", "Durian fruit", "Rambutan"); |
Here is how the list can be created in Java 8:
1 2 |
List<String> fruitList = Arrays.asList("Star apple", "Durian fruit", "Banana", "Rambutan"); fruitList = Collections.unmodifiableList(fruitList); |
Java 9 also provide us the convenience static factory methods of the Set interface, please visit Create An Immutable Set In Java 9 By Static Factory Methods for more detail.
3. Characteristics of The Immutable List Static Factory Methods
As we can see from above, the List.of() static factory methods provide a convenient way to create immutable lists. And the List instances created by these methods have the following characteristics:
- They are structurally immutable. Elements cannot be added, removed, or replaced. Calling any mutator method will always cause UnsupportedOperationException to be thrown, for example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
@Test public void testImmutableListNotModified() { List<String> cerealMix = List.of("Papaya", "Raisin", "Dried Apple", "Dried Peach"); assertEquals(4, cerealMix.size()); assertThrows(UnsupportedOperationException.class, () -> { // Add more element cerealMix.add("Wheat"); // Remove element cerealMix.remove(1); }); } |
- However, they can contain elements are themselves mutable, this may cause its contents to appear to change, for example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
@Test public void testImmutableListMutableElements() { Map<Integer, String> numbersMap = new HashMap<>(); numbersMap.put(1, "One"); numbersMap.put(2, "Two"); Map<Integer, String> currencyMap = new HashMap<>(); currencyMap.put(100, "Hundreds"); currencyMap.put(1000, "Thousands"); List<Map<Integer, String>> numCurrList = List.of(numbersMap, currencyMap); assertEquals(2, numCurrList.get(0).size()); //Add more elements to the mutable element of the List numbersMap.put(3, "Three"); numCurrList.get(0).put(4, "Four"); assertEquals(4, numCurrList.get(0).size()); } } |
- They disallow null elements. If we attempt to create them with null elements then a NullPointerException will be thrown, for example:
1 2 3 4 5 6 7 8 |
@Test public void testImmutableListNullAttempts() { assertThrows(NullPointerException.class, () -> { List<String> stringList = List.of(null); }); } |
- The order of elements in the list is the same as the order of the provided arguments, or of the elements in the provided array, for example:
1 2 3 4 5 6 7 8 9 10 |
@Test public void testImmutableListOrdered() { List<?> coffeeList = List.of("Espresso", "Latte", "Cappuccino"); assertEquals("Espresso", coffeeList.get(0)); assertEquals(2, coffeeList.indexOf("Cappuccino")); } |
- They are serializable if all elements are serializable and they are serialized as specified on the Serialized Form page, for example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
@Test public void testImmutableListSerializable() throws IOException { List<String> drinks = List.of("Coffee", "Wine", "Fruit"); //serialize the list ObjectOutputStream oos = new ObjectOutputStream(System.out); oos.writeObject(drinks); //create a list of non-serializable objects List<OutputStream> outputStreamList = List.of(new ByteArrayOutputStream(), new PrintStream(System.out)); assertThrows(NotSerializableException.class, () -> { oos.writeObject(outputStreamList); } ); } |
4. Conclusions
The tutorial has illustrated about the immutable List static factory methods and how to use those to create immutable Lists in Java 9. We can see that the immutable methods are very convenient for us to initialize a list from known values, and that never changes. And we always should consider using these methods if our data changes infrequently.
Below are related articles for your references:
Install Oracle Java 9 on CentOS, RHEL 7
Install Oracle Java 9 on Ubuntu 16.04 LTS (Xenial Xerus)
Private Interface Methods In Java 9
Using The InputStream.transferTo() To Copy Streams In Java 9
How To Compare Arrays In Java 9
Java 9 – Effectively Final Variables In try-with-resources
Java 9 HTTP/2 Client API Example