skip to content

How do you pass an existing array into a Java (or Kotlin) vararg parameter, and what does the * operator do?

level: middleimportance: must knowfreq 65%

answer

  1. = spread operator, unpacks array into varargs
  2. foo(*arr) not foo(arr)
  3. Can mix: f("a", *arr, "z")
  4. int... needs IntArray, not Array<Int>
  5. Spread copies elements (not free)

basics

~10 s

Use the spread operator: put * before the array, like foo(*arr). It unpacks the array so each element is passed as a separate vararg argument instead of one array argument.

solid answer

~40 s

A Java varargs method `void f(String... xs)` is, on the JVM, just `void f(String[] xs)`. To forward an existing array into it, Kotlin requires the spread operator `*`: `f(*arr)`. Without `*`, Kotlin would treat the array as a single argument, which fails type-checking for varargs. You can mix spreads with literals: `f("a", *arr, "z")`, and even spread multiple arrays. The element array type must match the vararg type: a `String...` (i.e. `String[]`) needs an `Array<String>`; an `int...` (`int[]`) needs an `IntArray`. Spreading copies the elements into a fresh array the callee receives, so it is not a zero-cost alias of the original.

code

kotlin · 7 lines
kotlin
// Java: static String join(String... parts)
val parts = arrayOf("x", "y", "z")
val s1 = Joiner.join(*parts)            // x,y,z
val s2 = Joiner.join("head", *parts)   // head,x,y,z

fun sum(vararg n: Int) = n.sum()
sum(*intArrayOf(1, 2, 3))               // 6 (IntArray spread)

go deeper

for a junior

Knows the * spread operator forwards an array into a vararg call.

for a middle

Explains varargs == array on the JVM, mixing spreads with literals, and that * is mandatory in Kotlin.

for a senior

Notes primitive-vararg array type rules and the copy semantics / allocation cost of spreading.

for a principal

Considers API ergonomics of vararg vs array params across the Java boundary and performance of repeated spreads in hot code.

## Varargs are arrays underneath On the JVM a varargs parameter is sugar for an array. Java's `void log(String... parts)` compiles to `void log(String[] parts)`. Kotlin's `fun log(vararg parts: String)` is the same: inside the function `parts` has type `Array<out String>`. ## The spread operator `*` When you already hold an array and want its elements to become the individual vararg arguments, you prefix it with `*` (the **spread operator**): ```kotlin val items = arrayOf("a", "b", "c") log(*items) // same as log("a", "b", "c") ``` Without the spread, `log(items)` would attempt to pass the whole `Array<String>` as one `String` argument and fail to compile. The spread is **mandatory** in Kotlin for forwarding an array to a vararg — unlike Java, where you can pass an array directly. ## Mixing spreads with normal arguments Spreads compose with literals and with other spreads: ```kotlin val mid = arrayOf("b", "c") log("a", *mid, "d") // a, b, c, d val more = arrayOf("e") log(*mid, *more) // b, c, e ``` ## Type must match the vararg element type - `fun f(vararg xs: String)` / Java `String...` -> spread an `Array<String>`. - `fun g(vararg xs: Int)` / Java `int...` -> spread an **`IntArray`** (primitive vararg uses the specialized array). Spreading an `Array<Int>` there is a type error; convert with `.toIntArray()` first. ```kotlin fun g(vararg xs: Int) = xs.sum() val p = intArrayOf(1, 2, 3) g(*p) // OK // g(*arrayOf(1,2,3)) // error: Array<Int> not IntArray ``` ## Copy semantics The spread produces a (shallow) **copy** of the elements into the array the callee actually receives, so the callee mutating its parameter does not affect your original array. It is not a zero-allocation pass-through. ## Recap - `*arr` = unpack array into separate vararg arguments. - Required to forward arrays to varargs in Kotlin. - Primitive varargs need the specialized array type.

  • Why does Java let you pass an array to varargs without any operator, but Kotlin requires *?
    Kotlin separates the array-as-single-argument case from element-by-element forwarding; the explicit * removes that ambiguity, so passing a bare array to a vararg is a compile error.
  • Can you spread two arrays into the same vararg call?
    Yes: f(*a, *b) is allowed; Kotlin builds one combined array from both plus any literal arguments.

The array is a sealed bag of letters; * tears the bag open and drops each letter into the mail slot one by one, instead of stuffing the whole bag through.

saying these in an interview costs you the question

  • Passing the array without * and expecting it to expand
  • Thinking * is pointer dereference or multiplication
  • Spreading Array<Int> into an int... parameter
  • Believing spread aliases the original array (it copies)

context