Overview

Convenience Factory Methods for Collections defines several factory methods for conveniently creating instances of unmodifiable collections and maps with small numbers of elements.

It is to ease the pain of not having collection literals in the Java programming language.

Why convenience factory methods are required?

Creating a small, unmodifiable collection (e.g. a list) involves constructing it, storing it in a local variable, and invoking add(), and then wrapping it. For example,

This is quite verbose, too much code for a simple task and it should be possible to be done in a single expression.

Alternatively, one can populate a collection using a copy constructor from other collection:

This is still somewhat verbose and also less obvious, since one has to create a List before creating the Set.

Another alternative is to use the so-called double brace technique:

The double brace technique is only a little less verbose but greatly reduces the readability.

However, it is not quite known, and it costs an extra class at each usage. It also holds hidden references to the enclosing instance and to any captured objects. This may cause memory leaks or problems with serialization. For these reasons, this technique is best avoided.

The Java 8 Stream API can be used to construct small collections, by combining stream factory methods and collectors. For example,

The Java 8 version, though, is a one-line expression, has some problems too. First, it’s not obvious and intuitive, second, it’s still verbose, third, it involves the creation of unnecessary objects and fourth, this method can’t be used to create a Map.

To summarize the shortcomings, one of the above approaches treat the specific use case creating a small unmodifiable Collection as a first class problem.

Each wrapper is an additional object, requiring another level of indirection and consuming more memory than the original collection.

Exploring the factory methods

Static methods have been provided on List, Set, and Map interfaces, which take the elements as arguments and return an instance of the List, Set and Map respectively. The method is named of(…) for all the three interfaces.

  1. List and Set

    The signature and characteristics of List and Set factory methods are same:

    For List and Set, these factory methods would work as follows:

    There are same overloaded methods for arguments of 1 to 10. If more are required, the var-args version can be used.

    Why fixed-argument methods? It avoids array allocation, initialization, and garbage collection overhead that is incurred by varargs calls.

    Significantly, the source code of the call site is the same regardless of whether a fixed-arg or varargs overload is called.

    During the creation of a Set using a factory method, if duplicate elements are passed as parameters, then IllegalArgumentException is thrown at runtime

  2. Map

    The signature of Map factory method is:

    For a Map, these factory methods would work as follows:

    Similarly to List and Set, the of(…) method is overloaded to have 0 to 10 key-value pairs.

    In the case of Map, there is a different method for more than 10 key-value pairs:

    and it’s usage:

Points to remember

The collections created using the factory methods are not the most commonly used implementations.

For example, the List is not an ArrayList and the Map is not a HashMap. They are different implementations which are introduced in Java 9. These implementations are internal and their constructors are not made public.

  1. Immutable

    The collections created using factory methods are immutable and changing an element, adding new elements or removing an element throws UnsupportedOperationException

    Due to this once collection is constructed and safely published, these collection/map instances will be safe for concurrent access in multiple thread contexts.

  2. No null Element Allowed and Fast Element access by Index

    In the case of List and Set, elements cannot be null. In the case of a Map, neither keys nor values can be null. Passing null argument throws a NullPointerException

    Because the List implementations are expected to provide fast element access by index, they implement the java.util.RandomAccess marker interface.

  3. Value-Based Instances

    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. Hence, if we create Lists with the same values, they may or may not refer to the same object on the heap

  4. Serialization

    Collections created from factory methods are Serializable if the elements of the collection are Serializable.

Conclusion

Java Enhancement Proposal (JEP) 269: Convenience Factory Methods for Collections’ small number of EnumSet-inspired factory methods minimize the pain of Java 9 not supporting collection literals. As well as reducing syntactic verbosity, these factory methods prevent any possibility of collection mutability, and so are amenable for use in Streams API-based or other parallelization contexts.

It's good to share...Share on FacebookTweet about this on TwitterShare on LinkedInPin on PinterestShare on Google+Email this to someone

Leave a Reply

Your email address will not be published. Required fields are marked *