skip to content

Element Access & Search

The retrieval family splits into throwing and null-returning forms — first versus firstOrNull, get versus getOrNull — plus single, find, and the take/drop slicing operators. Choosing the OrNull variant deliberately is what interviewers watch for.

part ofKotlinoverview, primer and where to startread it →
on this pageshow

questions

5

In Kotlin, what is the difference between accessing a list element with `list[i]`, `list.getOrNull(i)`, and `list.getOrElse(i) { default }`? When does each fail or succeed?

level: juniorimportance: must knowfreq 78%

answer

  1. [] throws, getOrNull → null, getOrElse → computed default
  2. getOrElse lambda receives the bad index
  3. map[key] is null-safe; getValue throws
  4. Pair getOrNull with ?: Elvis

basics

~10 s

list[i] throws an error if the index is out of range. getOrNull(i) returns null instead of throwing. getOrElse(i) { ... } returns a value you compute when the index is out of range.

solid answer

~40 s

`list[i]` calls `get(index)` and throws `IndexOutOfBoundsException` when the index is negative or `>= size`. `getOrNull(i)` is a safe variant returning `T?` — it gives `null` for any out-of-bounds index instead of throwing. `getOrElse(i) { idx -> ... }` returns a computed fallback (the lambda receives the bad index) and never throws. Use `[]` when the index is provably valid (e.g. from `indices`), `getOrNull` when you want to branch with `?:` or `?.let`, and `getOrElse` when you have a meaningful default. None of these mutate the list. For maps the analogue is `map[key]` (returns `V?`, no throw) versus `getValue(key)` (throws `NoSuchElementException`) and `getOrDefault`/`getOrElse`.

code

kotlin · 5 lines
kotlin
val xs = listOf(10, 20, 30)
val a = xs[2]                       // 30
val b = xs.getOrNull(9)             // null
val c = xs.getOrElse(9) { it * 0 }  // 0 (lambda gets index 9)
val d = xs.getOrNull(9) ?: -1       // -1

go deeper

for a junior

Knows [] throws and getOrNull returns null; can pick the right one for a bounds-uncertain index.

for a middle

Uses getOrElse with the index parameter and composes getOrNull with Elvis/let; knows the map analogues.

for a senior

Explains O(1) vs O(n) for List vs Sequence access and argues against exception-driven control flow.

for a principal

Sets team conventions: prefer total accessors at boundaries, reserve [] for provably-valid indices from indices/lastIndex.

## The three access forms Kotlin's `List` exposes element access through the indexed-access operator and several safe helpers. - **`list[i]`** — sugar for `list.get(i)`. The `get` member is defined on `List<E>` and throws `IndexOutOfBoundsException` when `i < 0` or `i >= size`. Use it only when the index is guaranteed valid. - **`list.getOrNull(i)`** — an extension on `List<T>` returning `T?`. It performs a bounds check (`if (index in indices) get(index) else null`) and returns `null` for any out-of-range index. Great with the Elvis operator: `list.getOrNull(i) ?: fallback`. - **`list.getOrElse(i) { idx -> ... }`** — an extension returning `T`. When in bounds it returns the element; otherwise it invokes the lambda, **passing the requested index**, and returns its result. Never throws. ```kotlin val xs = listOf("a", "b", "c") xs[1] // "b" xs.getOrNull(5) // null (no throw) xs.getOrElse(5) { "?" } // "?" xs.getOrElse(5) { idx -> "missing@$idx" } // "missing@5" ``` ## Why not just catch the exception? Using `getOrNull`/`getOrElse` expresses intent and avoids exception-driven control flow, which is slower and obscures logic. The `?:` and `?.let { }` operators compose cleanly with the nullable result. ## Maps are different For `Map<K, V>`: - `map[key]` returns `V?` and never throws (absent key → `null`). - `map.getValue(key)` throws `NoSuchElementException` if the key is absent. - `map.getOrElse(key) { default }` and `map.getOrDefault(key, default)` supply fallbacks. ## Edge cases - Negative indices are out of bounds for all of these. - `getOrNull`/`getOrElse` are O(1) on `List` (random access) but on a `Sequence` or `Iterable` the analogous `elementAtOrNull` is O(n) because it iterates.

  • What does the lambda passed to getOrElse receive?
    The requested (out-of-bounds) index, so you can build a message or compute an index-dependent default.
  • How do you do the same safe access on a Map?
    Use map[key] (returns V?, never throws) or map.getOrElse(key) { default } / getOrDefault; getValue throws on a missing key.

Like asking for a book by shelf number: [] crashes if the slot is empty, getOrNull hands you nothing, getOrElse hands you a substitute you chose.

saying these in an interview costs you the question

  • Claiming list[i] returns null when out of bounds (it throws)
  • Saying getOrNull throws an exception
  • Wrapping every access in try/catch instead of using the safe accessors
  • Thinking getOrElse's lambda receives the element rather than the index
  • Confusing map.getValue (throws) with map[key] (null-safe)

context

open as a page

Compare `first()`, `firstOrNull()`, `find { }`, and `first { }` in Kotlin. What exceptions can they throw and how do they relate?

level: middleimportance: must knowfreq 80%

basics

~20 s

first() returns the first element but throws if the collection is empty. firstOrNull() returns null instead. first { predicate } returns the first matching element (throws if none); find { predicate } is the same but returns null if none match.

open as a page

What are the exact semantics of `single()`, `singleOrNull()`, `single { }`, and `singleOrNull { }` in Kotlin? When would you choose single over first?

level: middleimportance: should knowfreq 58%

basics

~20 s

single() returns the only element and throws if the collection is empty OR has more than one. singleOrNull() returns null in both of those cases. The predicate versions do the same but for elements matching a condition.

open as a page

How do `contains`/`in`, `indexOf`, and `indexOfFirst { }` work in Kotlin collections? What are the performance and equality considerations across List, Set, and Map?

level: seniorimportance: should knowfreq 55%

basics

~20 s

x in list (or list.contains(x)) checks if an element is present. indexOf(x) returns its position or -1 if absent. indexOfFirst { } finds the position of the first element matching a condition, or -1. Sets and maps check membership much faster than lists.

open as a page

Explain `take`, `drop`, `takeLast`, `dropLast`, `takeWhile`, `dropWhile`, and `slice` in Kotlin. How do they handle out-of-range counts and what do they return?

level: seniorimportance: should knowfreq 60%

basics

~20 s

take(n) keeps the first n elements; drop(n) skips them. takeLast/dropLast work from the end. The While versions cut at the first element that fails a condition. slice picks elements by index range or list. They return new collections and don't mutate.

open as a page