Start learning free

LESSON 90 OF 348 · ARRAYS I

ArrayList in Kotlin: mutableListOf and MutableList

Lesson Read the full explanation

A big limitation of static arrays in Kotlin is the fact that once the array is created, it has a fixed size.

The ArrayList overcomes this limitation by having variable size and allowing for elements to be added or removed.


Creation:

We create an ArrayList by calling the mutableListOf() function, writing the type of the elements inside <> (angle brackets), like this:

mutableListOf<String>()

This code creates an empty ArrayList where each item is a String.


Casting:

A good practice is to declare the variable using its interface type MutableList and specifying there the type of the elements, like this:

val sandwich: MutableList<String> = mutableListOf()

Initialization:

You can also initialize an ArrayList at creation by passing the elements to mutableListOf() and put a comma between each entry, like this:

val sandwich = mutableListOf("peanut butter", "jelly", "bread")

We created an ArrayList named sandwich which consits of 3 items: "peanut butter", "jelly" and "bread".


Assignment
Follow the Coding Tutorial and let's create some ArrayLists!


Hint
Look at the examples above if you get stuck.


STEP 1 OF 2
    Ctrl + Enter to check

    KOTLIN · ARRAYS I

    Arrays in Kotlin, explained

    Why use a list

    A static array has a size fixed at creation. When the number of items changes while the program runs, you want a collection that can grow and shrink. In Kotlin that is a MutableList, and the usual implementation behind it is ArrayList, a resizable array. You create one by calling mutableListOf.

    Creating a list

    An empty list needs to know the type of its elements, because nothing else tells the compiler:

    val names = mutableListOf<String>()
    println(names.size)
    names.add("kiwi")
    names.add("mango")
    println(names)
    
    0
    [kiwi, mango]
    

    Unlike an array, a list prints its elements directly. add appends to the end, so the size grows from 0 to 2 here.

    Declaring the type

    You can also write the variable's type yourself, using the interface MutableList:

    val sandwich: MutableList<String> = mutableListOf()
    

    Here the type on the left tells Kotlin what mutableListOf() should hold, so the call needs no <String>. Declaring the interface type, rather than ArrayList, says what you need (a list you can change) without tying the code to one implementation.

    Creating a list with values

    When you know the values, pass them to mutableListOf:

    val sandwich = mutableListOf("peanut butter", "jelly", "bread")
    

    Kotlin infers the element type, String, from the arguments, so no annotation is needed.

    Mutable and read-only lists

    Kotlin separates lists you can change from lists you can only read. listOf(1, 2) gives a read-only List: it has no add, and assigning to an index doesn't compile. mutableListOf gives a MutableList, which has add, removeAt and index assignment. Choose mutableListOf when the contents will change.

    Also note that val and mutability are separate things. val stops you from pointing the variable at another list. It doesn't stop you from adding to the list it already points to.

    The exercise

    1. Create fruits. Call mutableListOf with the three strings. The element type is inferred as String.
    2. Create ages. Call mutableListOf with the four numbers. The type is inferred as Int, and because the list is mutable, it can grow or shrink later.
    val fruits = mutableListOf("mango", "kiwi", "grapefruit")
    val ages = mutableListOf(14, 32, 50, 21)
    

    The exercise prints nothing. Adding println(fruits) shows [mango, kiwi, grapefruit] and println(ages) shows [14, 32, 50, 21].

    Common mistakes

    • Using listOf when you need to change the list. Calling add on a read-only list gives an "unresolved reference" error.
    • Forgetting the type for an empty list. val items = mutableListOf() doesn't compile, because there are no values to infer the type from. Write mutableListOf<String>() or give the variable a type.
    • Mixing types. mutableListOf(1, "a") compiles, but the compiler can no longer treat the elements as Int or as String, which is rarely what you want.
    • Thinking val makes the list constant. It doesn't; use listOf if you want a list that can't change.

    Changing a list

    The point of a mutable list is that it can change size. Three operations you will use often are add, which appends an item to the end; removeAt, which deletes the item at an index; and remove, which deletes the first item equal to a given value. The contains function tells you whether a value is present.

    val sandwich = mutableListOf("peanut butter", "jelly")
    sandwich.add("bread")
    sandwich.removeAt(0)
    println(sandwich)
    sandwich.remove("jelly")
    println(sandwich)
    println(sandwich.contains("bread"))
    
    [jelly, bread]
    [bread]
    true
    

    Each call changes the same list in place. That is why sandwich can be a val: the variable keeps pointing at one list while the list's contents change.

    Lists compared with arrays

    An array made with arrayOf or IntArray has a fixed size and prints as an unreadable type name unless you call contentToString(). A list can grow, shrinks when you remove items, and prints its elements directly. For numbers, an IntArray stores plain values, while a MutableList<Int> stores boxed objects, so an array is a bit leaner when the size is known up front. When it isn't, a list is the better fit.

    Key takeaways

    • mutableListOf creates a resizable list backed by an ArrayList.
    • Give the type in angle brackets or on the variable when the list starts empty.
    • listOf is read-only; mutableListOf allows add and removeAt.
    • val fixes the variable, not the contents.
    Keep going with KotlinAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free