skip to content

How does `for ((key, value) in map)` work, and what enables destructuring a `Map.Entry` and lists/arrays?

level: middleimportance: should knowfreq 60%

answer

  1. Map iterates as Map.Entry
  2. Entry.component1()=key, component2()=value
  3. List/array: component1()..component5() only
  4. Over-reading a list throws IndexOutOfBoundsException
  5. withIndex() -> (index, value)

basics

~10 s

Iterating a map yields Map.Entry objects, and each entry can be unpacked into key and value because Map.Entry provides component1() (key) and component2() (value). Lists and arrays provide component1()..component5() too.

solid answer

~40 s

A `Map` is iterable as a sequence of `Map.Entry<K, V>`. The standard library adds `operator fun <K,V> Map.Entry<K,V>.component1() = key` and `component2() = value` as extension functions, so `for ((key, value) in map)` destructures each entry positionally: slot 1 = key, slot 2 = value. The same mechanism powers `map.forEach { (k, v) -> ... }`. For `List` and arrays, the stdlib provides extension `componentN()` operators for the first five elements (`component1()`..`component5()`), so `val (first, second) = listOf(1, 2, 3)` works but only up to index 5 — `component6()` doesn't exist, so a 6th destructured variable won't compile. Out-of-range access (e.g. destructuring 3 elements from a 2-element list) throws `IndexOutOfBoundsException` at runtime.

code

kotlin · 6 lines
kotlin
val scores = mapOf("Ada" to 90, "Linus" to 85)
for ((name, score) in scores) println("$name: $score")

for ((i, name) in listOf("a", "b").withIndex()) println("$i=$name")

val (first, second) = listOf(1, 2, 3) // first=1, second=2

go deeper

for a junior

Can write for ((k, v) in map) and knows it gives key then value.

for a middle

Explains Map.Entry's component1()/component2() extensions and the five-component limit on lists.

for a senior

Distinguishes compile-time (no component6) from runtime (IndexOutOfBoundsException) failure modes and mentions withIndex/IndexedValue.

for a principal

Advises against destructuring lists in production paths due to silent runtime index failures, preferring explicit indexing or pattern-safe accessors.

## Map iteration Iterating a `Map` produces `Map.Entry<K, V>` elements. The Kotlin standard library declares extension operators: ```kotlin operator fun <K, V> Map.Entry<K, V>.component1(): K = key operator fun <K, V> Map.Entry<K, V>.component2(): V = value ``` So the loop: ```kotlin for ((key, value) in mapOf("a" to 1, "b" to 2)) { println("$key=$value") } ``` is rewritten to call `entry.component1()` (the key) and `entry.component2()` (the value). The same works in lambdas: ```kotlin mapOf("a" to 1).forEach { (k, v) -> println("$k -> $v") } ``` ## Lists and arrays The stdlib provides `component1()` through `component5()` as extensions on `List` and on array types: ```kotlin val (a, b, c) = listOf(10, 20, 30, 40) // a=10, b=20, c=30 (4th ignored) ``` Limits and pitfalls: - Only **five** component operators exist for lists/arrays. `val (a,b,c,d,e,f) = list` won't compile — there is no `component6()`. - These do **index access**, so destructuring **more elements than the collection holds** throws `IndexOutOfBoundsException` at runtime (the compiler can't know the size). ```kotlin val (x, y) = listOf(1) // compiles, but throws IndexOutOfBoundsException at runtime ``` ## withIndex A common pairing is `for ((index, item) in list.withIndex())`, where `withIndex()` returns `IndexedValue`, itself destructurable into index and value. ## Why this matters Map/list destructuring is the most frequent real-world use of the feature. Knowing it is extension-driven explains why arbitrary deep collections aren't fully destructurable and why over-reading a list fails at runtime rather than compile time.

  • Why can't you destructure six elements out of a list?
    The stdlib only defines component1() through component5() for List/array. There's no component6() operator, so a sixth destructured variable fails to compile.
  • What happens if you destructure three variables from a two-element list?
    It compiles, but component3() does an index-2 access on a size-2 list, throwing IndexOutOfBoundsException at runtime.

saying these in an interview costs you the question

  • Thinking map keys/values are matched by variable name
  • Assuming lists support unlimited componentN()
  • Expecting a compile error for over-reading a list (it's runtime)
  • Confusing Map.Entry with Pair

context