Kotlin Lists are Read-only and not Immutable except when there is only 1 element
I’d always assumed that List
in Kotlin is immutable, but while writing another post, I learnt that it is technically read-only and not immutable, as it can actually be mutated using several methods.
MutableList
is a subclass of List
, and when a MutableList
is assigned to a List
, it can still be mutated using the reference to the MutableList
.
List
can also be cast into MutableList
and then mutated. This means that if you pass a List
into another method, there is a chance that your original list is changed.
The “safe” way to mutate a List
is to use the toMutableList()
method. This creates a copy of the original List
and returns a MutableList
.
However, a single-element List
created via listOf()
is immutable. However, do note that this is not caught at compile time.
An aside: this difference is by design, due to the way Kotlin represents List in Java. If we decompile into Java, this is what happens behind the scenes:
val list1 = listOf(1)
val list2 = listOf(1, 2)
...becomes...
@NotNull
private static final List list1 = CollectionsKt.listOf(1);
@NotNull
private static final List list2 = CollectionsKt.listOf(new Integer[]{1, 2});
...and CollectionsKt.listOf is...
public fun <T> listOf(element: T): List<T> = java.util.Collections.singletonList(element)
java.util.Collections.singletonList
is immutable! But since multi-element lists get created as an array, that effectively makes it mutable.
Above being said, if we only use List
in Kotlin code, and not assign it from or cast it to MutableList
, or pass it to or from Java, then it can safely be said to be immutable, since it does not have set()
or add()
methods.
Here’re some articles you might like: