Basic Collections: Introduction
Why Java collections are extremely problematic, and how Kotlin takes a different approach. A description of all the different methods to create collections — construction from elements, builder functions, concrete type constructors/initializer functions, copying and invoking functions on other collections.
— — — — — — — — — — — — — — —
THE CURRENT VERSION OF THIS ARTICLE IS PUBLISHED HERE.
— — — — — — — — — — — — — — —

Tags: #FYI++
This article is part of the Kotlin Primer, an opinionated guide to the Kotlin language, which is indented to help facilitate Kotlin adoption inside Java-centric organizations. It was originally written as an organizational learning resource for Etnetera a.s. and I would like to express my sincere gratitude for their support.
It is recommended to read the Introduction before moving on. Check out the Table of Contents for all articles.
The Java status quo
One of the biggest failures of Java collections is that they are mutable by default — for example, java.util.List describes a mutable list. This is a pretty serious problem, because it breaks the ‘L’ (which stands for Liskov Substitution Principle) in SOLID, namely that subclasses are always usable in place of their superclasses.
To see how, think about how you would implement an immutable list in Java. Naturally, you’d want it to implement the java.util.List interface, because that’s what everyone uses, but that interface describes a mutable list — it defines methods such as add, remove etc. In order to conform to this interface, you have no choice but to implement these by throwing an exception, which is exactly what e.g. Guava does in its ImmutableList implementation.
Unfortunately, what this means is that your implementation cannot be used safely wherever it’s parent (e.g. List) can. You can call add on List, but you can never be sure it won’t throw an exception. I can pass a Guava ImmutableList anywhere a List is expected with no complaint from the compiler, and introduce a runtime error just like that. And as we’ve said many times before, runtime errors are your worst enemy!
What’s even worse is that Java actively encourages you to do this, which is just beyond comprehension. So, to sum it up, in Java:
- When implementing an immutable list, we have the choice of either implementing
List, thereby breaking the Liskov Substitution Principle, or not implementingList, thereby making our implementation practically unusable - We have no way to enforce immutability at the declaration site (e.g. when defining a method parameter) without tying our declaration to a specific implementation
- We risk causing runtime errors when we pass an immutable implementation at the call site (e.g. when calling a method). To prevent this, we need to study all code that will interact with our implementation, which breaks encapsulation.
And, worst of all, there’s no fixing this without breaking backwards compatibility — Java has no choice but to stick with this sad state of affairs.
Kotlin to the rescue
The core problem is that, in Java, immutable collections are modeled as subclasses of mutable collections, when in reality, it’s the other way around. A mutable collection contains more functionality than an immutable version — it’s an immutable collection + methods that allow it to be mutated. It needs to be a subclass of its immutable variant. And this is exactly how Kotlin defines its collections.

It should be noted that so far, we’re only talking about interfaces. Iterable, List, MutableMap etc. are all interfaces, not actual implementations. The actual implementations are always mutable, but that doesn’t matter — if a method is expecting a List<T>, and List is an immutable interface, then we can safely send in a mutable implementation (e.g. ArrayList<T>) and everything will be fine, because every mutable implementation implements List. And by implements, I mean actually, safely implements, as opposed to implements but throws exceptions sometimes.
Naturally, Kotlin collections are compatible with Java. Java versions will get cast to the appropriate platform type when used in Kotlin code.
As can be seen above, the fundamental collections are List, Set and Map, and a quick overview can be found in the docs.
Constructing collections
The most basic, and most often used, way to construct collections are using the xOf() methods — listOf() for an immutable List instance, mutableSetOf() for a mutable Set instance, and so on. For the most part, their usage is fairly straightforward. The only nontrivial aspect is constructing instances of Map, where you specify key-value pairs using instances of Pair. The to infix function, which we mentioned briefly in the article on data classes, can be taken advantage of:







