Java 9 - Collection Factory methods


Hi, I am Malathi Boggavarapu working at Volvo Group and i live in Gothenburg, Sweden. I have been working on Java since several years and had vast experience and knowledge across various technologies.

Let's jump start into Java 9 features

Collection Factory methods

Java9 provides some collection factory methods for creating List, Set and Map in more convenient way.

Collections: The traditional way

1) Here we use many lines of code to create a small immutable collection of List of books. It is very verbose using the traditional way.

List<String> books = new ArrayList<String>();
books.add("Java 9");
books.add("Java 8");
books.add("Java 7");
books.add("Java 6");

2) There is one more way to create a list of books. We can use Arrays class to create a List. 

List<String> books = Arrays.asList("Java 9 Modularity", ..);
It's bit weird that you do it using Arrays class. Is not it? And also we can construct only Lists but not Sets.

Then there were clever people who deviced this hack. You can anonymously instantiate a collection class as below

List<String> books = new ArrayList<>() {{add("Java 9 Modularity");}};

If this does not make sense to you, that's perfectly fine. I wouldn't recommend this way at all.
Lastly, there are some methods in Collections class to create empty list and empty set but they just create empty classes.

Collections: Java 9 way

In java9, we have got some collection factory methods to create a List or Set in a single line.
We use JShell to illustrate this now.


Above you can see, we create a list with single line code. It returns list of Intergers and the list is immutable. If we try to add elements to the immutable list, JShell throws UnsupportedOperationException.

Let's dig into little more deeper. When we call ints.getClass as shown in above picture, it returns implementation class ListN. This is the new type of collection class. Well the implementation class also differ according to the number of elements in the List. For example if the List contain one element, the implementation class would be List1 and if the List contain two elements, the implementation class would be List2. Those two classes are super optimized implementations of single and dual element lists. Anything above 2 elements in the List will be of instance of type ListN.

Well these are just the implementation details but it is nice to know that there are optimizations that are done for the collection factory methods.

There are 12 overloaded versions of this method. 11 overloaded methods will be from 0 to 10 parameters and one method which takes var-args.

List.of()
List.of(E e1)
List.of(E e1, E e2)
List.of(E e1, E e2, E e3)
// ...... and so on

List.of(E... elements)

For most practical purposes, 10 elements are required but if we want more elements to be added to the List, we can use var-args method. Now a question may arise, what is the point of having 11 extra methods if there is var-args version which can work for any number of elements.

The answer to it is Performance. Every time multiple elemnts are passed to var-args method, they are packed into a new array because internally var-args are passed as arrays. To avoid the overhead of intermediate array allocation, static overloads upto 10 elements for the of method are defined. This is quite ugly from the API specification perspective but it does give you List factory methods upto 10 elements without any intermediate allocations. If you use an IDE with auto-completion don't be surprised to see so many overloads for the List.of() method.

We can also create a Set using new Collection factory methods. See the picture below. We can create a Set using one line of code using Set.of(..) method. If we are trying to add null values or similar elements to Set , it throws exception. See below.

Like List, we have similar number of overloaded methods for Set.



Map

Just like Set and List, we have of method for Map. See the below picture which illustrates the creation of Map in JShell console.








We should make sure the number of parameters is even. If we provide odd number of parameters, for example with out passing value for the key "key3" JShell gives type checking errors which means this code does not compile.

There is also second factory method for Map called ofEntries(). We pass Map.Entry instances to this method. See the below picture which illustrates it in JShell.



We can pass any number of Map.entry instances to the ofEntries method which creates key, value pairs in the Map. Like Sets we can not pass duplicate keys and values. This results in IllegalArgumentException. Try it!!!!

Again if we look after API, we have 10 overloaded Map.of methods just like List and Set as described above.

Map.of(K key1, V value1)
Map.of(K key1, V value1, K key2, V value2)
// ....... so on upto 10 key, value  pairs
Map.ofEntries(Map.Entry<K,V>... entries)

The last method accepts unbounded number of Map.Entry instances. So we can create any number of key,value pairs.

Important Note

Iteration order of the Maps and Sets returned by the factory emthods are not gauranteed.

So that's all about this course. Hope its helpful. Please post your comments and make the session more interactive.

Happy Learning!!

Comments

Popular posts from this blog

Bash - Execute Pl/Sql script from Shell script

How to get client Ip Address using Java HttpServletRequest

How to install Portable JDK in Windows without Admin rights