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.
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
| Type | Built with | Use it for |
|---|---|---|
List<Int> | listOf(1, 2) | almost everything |
MutableList<Int> | mutableListOf(1, 2) | when you must add or remove |
IntArray | intArrayOf(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:
| Call | Availability |
|---|---|
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.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…