skip to content

Walk through the conversions between Array<T>, primitive arrays, and collections (toTypedArray, toIntArray, toList, etc.).

level: middleimportance: should knowfreq 60%

answer

  1. toIntArray = unbox to int[]
  2. toTypedArray = box to Array<T>
  3. toList/toSet = copy into collection
  4. asList = view, no copy, tracks writes
  5. spread * passes array into vararg

basics

~10 s

Use toTypedArray() to get an Array<T>, toIntArray()/toLongArray() for primitive arrays, and toList()/toMutableList() for collections. Each one copies the data into a new container.

solid answer

~40 s

The conversions form a small grid. From a List<Int> or Array<Int>: .toIntArray() produces an unboxed IntArray; .toTypedArray() produces a boxed Array<Int>. From an IntArray: .toTypedArray() gives Array<Int> (boxing each element), and .toList()/.toMutableList() give collections. From any array: .toList(), .toSet(), .asList() (a lightweight read-only view, not a copy). Key point: to*Array and to*List all create a NEW backing structure (a copy), so mutating the source after conversion doesn't affect the result — except asList(), which is a wrapper view that reflects later element writes to the array. Conversions are also how you bridge the incompatible Array<Int> and IntArray types, since neither is assignable to the other.

code

kotlin · 8 lines
kotlin
val list = listOf(1, 2, 3)
val prim: IntArray = list.toIntArray()       // unboxed copy
val boxed: Array<Int> = prim.toTypedArray()  // boxed copy

val view = boxed.asList()   // view, no copy
boxed[0] = 42
println(view[0])            // 42  (asList reflects element writes)
println(prim[0])            // 1   (toIntArray was a copy)

go deeper

for a junior

Knows toList() and that some to...() function converts between arrays and lists.

for a middle

Maps the full grid: toIntArray/toTypedArray/toList and which direction each goes (box vs unbox).

for a senior

Distinguishes copy converters from the asList() view, explains the storage-sharing semantics, and uses the spread operator correctly.

for a principal

Reasons about allocation cost of conversions in hot paths and chooses views vs copies deliberately to avoid needless GC.

## The conversion grid Kotlin gives you copy-based converters to move between the three shapes — generic array `Array<T>`, primitive array (`IntArray`, …), and collections (`List`, `Set`). ### To a primitive array - `List<Int>.toIntArray()` / `Array<Int>.toIntArray()` -> **`IntArray`** (unboxes each element). - Equivalents: `toLongArray()`, `toDoubleArray()`, `toFloatArray()`, `toByteArray()`, `toShortArray()`, `toCharArray()`, `toBooleanArray()`. ### To a generic (boxed) array - `IntArray.toTypedArray()` -> **`Array<Int>`** (boxes each element). - `Collection<T>.toTypedArray()` -> **`Array<T>`**. ### To collections - `Array<T>.toList()` / `IntArray.toList()` -> read-only **`List`** (a copy). - `toMutableList()`, `toSet()`, `toMutableSet()`, `toHashSet()` — analogous copies. - `Array<T>.asList()` -> a **`List<T>` VIEW** wrapping the same array — **no copy**; element writes to the array are visible through it (but you still can't add/remove). ```kotlin val prim = intArrayOf(1, 2, 3) val boxed: Array<Int> = prim.toTypedArray() // int[] -> Integer[] val list: List<Int> = prim.toList() // copy val backToPrim: IntArray = list.toIntArray() // List -> int[] val view = boxed.asList() // wrapper, no copy boxed[0] = 99 println(view[0]) // 99 (reflects the write) ``` ## Copy vs view — the crucial distinction - **`to*Array` / `to*List`**: allocate a brand-new backing store and copy elements. Later mutations to the source do **not** leak into the result. - **`asList()`**: returns a fixed-size `List` **backed by** the original array. It is the cheap way to expose an array through the `List` API, and it tracks the array's element changes. ## Why conversions exist Because `Array<Int>` (boxed `Integer[]`) and `IntArray` (`int[]`) are **unrelated types** and neither is assignable to the other, `toTypedArray()`/`toIntArray()` are the bridge. They also help cross the array↔collection boundary when an API demands one shape. ## Spread operator note To pass an existing array into a `vararg` parameter, use the **spread operator** `*`: `printAll(*arrayOf("a", "b"))`. That is array-specific syntax, not a conversion function.

  • What's the difference between toList() and asList() on an array?
    toList() copies into a new immutable list; asList() returns a fixed-size view backed by the same array, so element writes to the array show up through it.
  • How do you pass an existing array into a vararg function?
    Use the spread operator: f(*myArray). It unpacks the array's elements into the vararg.

saying these in an interview costs you the question

  • Assuming to*Array shares storage with the source
  • Not knowing asList() is a view, not a copy
  • Mixing up toTypedArray (box) and toIntArray (unbox)
  • Forgetting the spread operator for varargs
  • Thinking you can assign IntArray to Array<Int> without conversion

context