In the previous post in the Java 9 series, we’ve introduced a new tool in the JDK toolbox – JShell. In this post, we’ll use JShell to showcase another useful feature in Java 9 – convenience factory methods for collections.

Thanks to JEP 269, Java 9 makes it really easy to create small, immutable collections, which was relatively tedious to do with the previous JDK releases. Every Java developer knows the drill – to create a small immutable collection, let’s say a list containing 3 strings, prior to Java 9, we would do the following:

There are several issues with this approach:

There are alternatives, of course. We could e.g.:

These alternative approaches help with verbosity, but they’re not particularly readable, require additional objects or dependencies as well as mutability support, or lack the desired flexibility (for example, there is no Arrays.asSet method, and Stream.of cannot be easily used to create maps).

Collection literals, syntactic constructs that evaluate to an aggregate type, would be an ideal solution to the problem. Wouldn’t an expression like the following be nice?

Unfortunately, adding new language features is hard, which is why JDK 9 introduced the next best thing – a library API consisting of convenient static factory methods on all the main collection interfaces (List, Set, Map), which allow us to create truly immutable collections. For example, we can create an immutable list using the List.of method:

The method is overloaded, quite a few times, actually. There are exactly 12 versions of it – methods for creating lists of 0-10 arguments, and a vararg method for bigger lists. While this not great for keeping the API clean, the reason we don’t have a single vararg method here is performance – there is overhead associated with allocating, initializing, and garbage collecting the array backing the vararg.

A list from our previous examples can then be created as follows:

It is truly immutable:

An interesting fact – the concrete classes returned by the convenience factory methods are not the popular ArrayList, HashSet, or HashMap. They are special implementations and are not part of the public API, which means that the callers can only rely on the interfaces. This allows the implementation to change in the future. The instances are obtained via static methods on interfaces, which are not inherited, and cannot be invoked via implementing classes or instances of the interface type. This is a very nice design pattern worth pointing out.

It should also be noted that the implementations of the immutable collections are serializable, and, like all modern collections, don’t support null elements, keys, or values.

The Set interface offers methods very similar to List:

And we can create a set as follows:

However, Map is a bit different:

Like lists and sets, we have separate methods for creating maps of 0-10 entries. As keys and values are specified one after another, the methods go up to 20 arguments. Unlike for lists and sets, there is no vararg version of the Map.of method. The reason is the fact that keys and values can be of different types, and Java doesn’t support methods with multiple varargs. To create a larger immutable map, we can take advantage of the Map.ofEntries method accepting a single vararg of Map.Entry:

That’s all there is to this API enhancement, really. Try it out!