Kotlin max value in the list
Video: Kotlin max value in the list by Taught by Celeste AI - AI Coding Coach
Kotlin: Max Value in a List
numbers.maxOrNull()returns the largest element ornullfor empty lists. The null-safe successor to the deprecatedmax(). Copilot's go-to one-liner for "find the biggest."
A one-liner with a small but important wrinkle — what happens when the list is empty?
The Copilot prompt
fun main() {
val numbers = listOf(3, 7, 2, 9, 4)
// Find the maximum value in the list
Copilot generates:
val maxValue = numbers.maxOrNull()
if (maxValue != null) {
println("The maximum value is $maxValue")
} else {
println("The list is empty")
}
maxOrNull vs max
Kotlin used to have max(), which threw NoSuchElementException on empty lists. It was deprecated in Kotlin 1.4 and replaced by maxOrNull().
val empty = emptyList<Int>()
println(empty.maxOrNull()) // null
// println(empty.max()) // would throw if it still existed
maxOrNull() is null-safe by design. The compiler forces you to handle the empty case explicitly — usually via !! (if you're sure), ?: (with a default), or ?.let { ... }.
Common patterns
// Default to 0 if empty
val max = numbers.maxOrNull() ?: 0
// Crash on empty (you're sure it's not)
val max = numbers.maxOrNull()!!
// Branch on empty
numbers.maxOrNull()?.let { println("Max: $it") } ?: println("Empty")
The Elvis operator ?: is the cleanest for "default value." Use !! only when the list is guaranteed non-empty by construction.
Max by a property
For complex objects, use maxByOrNull:
data class Person(val name: String, val age: Int)
val people = listOf(
Person("Alice", 30),
Person("Bob", 25),
Person("Charlie", 35),
)
val oldest = people.maxByOrNull { it.age }
println(oldest) // Person(name=Charlie, age=35)
maxByOrNull returns the element with the maximum key, not the key itself. To get just the max age:
val maxAge = people.maxOfOrNull { it.age } // 35 (the Int)
val oldest = people.maxByOrNull { it.age } // Person(...) (the whole object)
Both have null-safe variants and maxBy/maxOf non-null counterparts that throw on empty.
Min, sum, average — same shape
Kotlin's collection extension functions mirror each other:
numbers.maxOrNull() // largest
numbers.minOrNull() // smallest
numbers.sum() // sum (no null-safe variant; sum of empty is 0)
numbers.average() // mean as Double (NaN for empty)
people.maxByOrNull { it.age } // element with max age
people.minByOrNull { it.age } // element with min age
people.sumOf { it.age } // total age
sumOf { selector } is the modern variant; the older sumBy and sumByDouble were deprecated in favor of the type-inferred sumOf.
Finding all elements at the max
val all_oldest = people.filter { it.age == people.maxOf { it.age } }
If multiple people share the max age, maxByOrNull returns the first one. filter returns all of them.
For just the value count:
val maxAge = people.maxOf { it.age }
val countAtMax = people.count { it.age == maxAge }
Performance
maxOrNull walks the list once, O(n). For sorted lists, the max is just list.last() — O(1). Use whichever matches your data.
For repeatedly querying the max of a changing list, consider a heap (PriorityQueue) or sorted structure. Pure List doesn't optimize for repeated max-queries.
Common mistakes
Using max() (deprecated). Compiler warning, but works. Always migrate to maxOrNull() when you see it.
Force-unwrapping on user input. userInput.split(",").map { it.toInt() }.maxOrNull()!! crashes if input is empty. Use ?: with a default.
Confusing maxBy and maxOf. maxBy returns the element; maxOf returns the key. Both null-safe variants maxByOrNull and maxOfOrNull.
maxOf { ... } without thinking about types. maxOf { it.age.toDouble() } returns Double, not Int. Pay attention to the inferred return.
Calling maxOrNull() on a Sequence with side effects. Sequences are lazy; maxOrNull triggers iteration. If your sequence has expensive computations, evaluate them once.
What's next
Episode 10: Merge two lists in Kotlin. The + operator works on lists too — and it's the cleanest approach.
Recap
numbers.maxOrNull() for the max (or null if empty). Use ?: for a default, !! only when guaranteed non-empty. maxByOrNull { selector } for "max by property" (returns element); maxOfOrNull { selector } returns the key. Same shape for min*, sum*, average. Walks the list once — O(n).
Next episode: merging two lists.