Home United States USA — software Convenience Factory Methods for Collections in Java 9

Convenience Factory Methods for Collections in Java 9

167
0
SHARE

Java 9 has introduce convenience factory methods for collections. See their use in Lists, Sets, and Maps and how they have simplified how you code.
Java 9 doesn’t bring as many dramatic changes to our way of coding as its predecessor did, but surely we will have some fancy features — one of which I would like to present to you in this article. When I started coding in Groovy about 5 years ago, I was amazed by the collections support there — especially when it came to initializing an immutable list. I could do it in one simple line:
This year, I also started coding in Scala, and here we have some fancy tricks like:
or simply
At the same time, Java seemed to be torturing me with an add statement list:
Or the so-called « double-brace » initialization (which in fact isn’t any special Java feature, but rather a workaround benefiting from anonymous classes and initialization blocks):
Or using the Arrays API to convert an array to an ArrayList:
Lately, I could also benefit from the Stream API:
The last two options are the cutest ones, but why do I need to first create an array or a stream in order to create a list, and why can’t I just use the Collections API instead of the Arrays API or the Stream API? Well, I don’t even want to recall creating Sets or Maps in Java — thinking of it makes me wake up in a cold sweat in the middle of the night. Fortunately, the authors of Java 9 implemented JEP 269: Convenience Factory Methods for Collections, which simply provides a set of static factory methods supporting the creation of immutable collection instances. Saviors! Read on to get the overview of this feature.
Before we dig into the topic, you should know what immutable collections really are. They are collections that cannot be modified once they are created. What I mean by « modified » is that their state (references they hold, the order in which those references are being kept, and the number of elements) will stay untouched. Please note that if an immutable collection holds mutable objects, their state won’t be protected anyhow. Although immutable collections still implement List, Set, or Map interfaces, methods modifying their contents throw an UnsupportedOperationException. You will find sets of such methods in subsequent sections.
Implementation can be divided into two main parts. Firstly, the java.util package was enriched with the package-private ImmutableCollections class, which contains classes providing the immutability feature. Secondly, instances of those classes are being created with the help of static factory methods in already-existing interfaces, i.e. List, Set, and Map. In the following sections, you will find descriptions of both sets of functionalities per each collection interface.
An immutable list has an abstract base class AbstractImmutableList and four implementations:
Each of these types corresponds to the number of elements that are used to their creation. In the java.util. List interface, we have 12 static factory methods that use the above implementations to create immutable objects:
Methods that throw UnsupportedOperationException:
Apart from protecting the content of our list, we also get a validation that prevents us from initiating a list with a null value. Trying to run the following piece of code will end up with a NullPointerException:
Now, here is an example of how to properly create an immutable list:
An immutable set is implemented similarly to how we saw with the List interface. It has an abstract base class AbstractImmutableSet and four implementations:
That again correspond to the number of elements that are used to their creation. In the java.util. Set interface, we have 12 static factory methods:
Methods that throw UnsupportedOperationException:
Like with immutable lists, we cannot instantiate a Set with a null value:
You should also know that sets differ from lists in a way — they cannot have duplicate values. With the newly provided factory methods, we won’t be able to initialize an immutable Set passing more than one object of the same value — we will get IllegalArgumentException:
Now, here is an example of how to properly create an immutable set:
Before we describe the technical details of immutable maps, we should start with the concept of an entry (java.util. Map. Entry interface) — an aggregate of a key-value pair. From Java 9, we have yet another entry’s package private implementation — java.util. KeyValueHolder — an immutable container that prevents instantiating an entry with a key or value equal to null (throwing a NullPointerException if done so).
In order to create an immutable entry, we can use the following static factory method from the java.util. Map interface:
An immutable map has an abstract base class, AbstractImmutableMap, with three implementations:
Again we have the following set of factory methods inside the java.util. Map interface:
You can see that it differs from List or Set factory methods from the previous sections. Using one of the methods, we can create immutable maps that contain up to 10 elements. If we want to have a bigger one, we need to use the ofEntries method, accepting varargs of Entity. It shouldn’t be any surprise, as we can use varargs for only one argument in a method, so we have no way of passing keys and values of different types this way.
Like with lists and sets, we have some methods that throw an UnsupportedOperationException:
Regardless the way we create immutable maps, we won’t be able to instantiate it with a key, value, or whole entry equal to null. Below are the examples of code that will throw NullPointerExceptions:
Similarly to immutable sets, we cannot create a map with duplicate values. Trying to do so will end up throwing IllegalArgumentExceptions:
And here are some examples of how can we properly create immutable maps in Java 9:
Since Java 9’s arrival, creating immutable collections has been very convenient. We have a set of static factory methods for each interface that, apart from creating immutable objects, prevent us from inserting nulls or duplicates (in Set and Map).

Continue reading...