Skip to content
Lesson 13 of 19

Step 1 of 5 · Reading · ~3 min

Learn

Collections

Lists and Arrays

Kotlin splits every collection in two: a read-only interface and a mutable one. You choose which one your code is allowed to see.

fun main() {
    val fixed: List<Int> = listOf(3, 1, 2)
    val growing: MutableList<Int> = mutableListOf(3, 1, 2)

    growing.add(4)

    println(fixed)
    println(growing)
    println(fixed.size)
    println(fixed[0])
    println(fixed.last())
}

//> [3, 1, 2]
//> [3, 1, 2, 4]
//> 3
//> 3
//> 2

fixed has no add method at all — that call would not compile. This is the type system doing the work, not a runtime check.

Rendering diagram…

Read-only is not the same as immutable

Look at the diagram again: MutableList is a List. So a List variable can perfectly well be pointing at a list that somebody else is still changing. Read-only describes your access, not the object's nature.

fun main() {
    val backing = mutableListOf("a", "b")
    val view: List<String> = backing

    backing.add("c")
    println(view)
}

//> [a, b, c]

The second surprise runs the other way: val freezes the name, not the contents.

✓ Legal — the name still points at the same object:

val items = mutableListOf(1, 2)
items.add(3)

✗ Not legal — this would move the name to a different object:

val items = mutableListOf(1, 2)
items = mutableListOf(9)

Reading past the end

list[5] on a three-element list throws IndexOutOfBoundsException. When the index might not be there, ask for it safely instead:

fun main() {
    val crew = listOf("Ada", "Grace")
    println(crew.getOrNull(5))
    println(crew.getOrNull(5) ?: "nobody")
}

//> null
//> nobody

Lists versus arrays

TypeBuilt withUse it for
List<Int>listOf(1, 2)almost everything
MutableList<Int>mutableListOf(1, 2)when you must add or remove
IntArrayintArrayOf(1, 2)fixed size, no boxing, tight numeric loops
Array<Int>arrayOf(1, 2)fixed size, boxed — rarely what you want

IntArray compiles down to a Java int[], so the numbers sit directly in memory with no wrapper objects around them. Array<Int> stores boxed integers. For beginner code, use List and stop thinking about it.

Turning an input line into numbers

Every exercise from here on opens with the same three moves, so read them slowly:

fun main() {
    val nums = readLine()!!.split(" ").map { it.toInt() }
    println(nums)
    println(nums.size)
    println(nums.sum())
}

Given the input line 3 8 2, the output is:

[3, 8, 2]
3
13

split(" ") cuts the line at every space into a List<String>, and map { it.toInt() } converts each piece into an Int. If the line contains a stray double space, split hands you an empty piece and toInt() throws — call .trim() on the line first when the input might be untidy.

Finding the largest value

The standard library has given three different answers here over the years, which is worth knowing before a compiler surprises you:

CallAvailability
nums.max()present in early Kotlin, withdrawn around 1.5, reinstated in 1.7
nums.maxOrNull()Kotlin 1.4 and later; the result type is Int?
nums.sorted().last()every version

When you do not know which compiler your code will meet, sorted().last() or a plain loop always works.

Your exercise

Largest Number reads one line of space-separated integers and prints the biggest of them.

The starter already splits the line and converts each piece for you. The mistake the grader catches is the classic accumulator seed: starting from var best = 0 and replacing it only when a number is larger. A hidden test feeds -3 -1 -7, where every value is below zero, so that version prints 0 instead of -1. Seed from the first element with var best = nums[0], or use one of the calls in the table above. Print the number alone on one line.

Up nextMaps and SetsCollections

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…