Question
Convert a Kotlin Array to Java varargs: Passing Arrays to Java Methods from Kotlin
Question
I have a Kotlin array of strings and I want to pass it to a Java method that accepts varargs (which appears as String... in Java and String[] in interop). For example:
val angularRoutings = arrayOf("/language", "/home")
// This does not work
web.ignoring().antMatchers(angularRoutings)
How do I correctly pass a Kotlin Array<String> to a Java varargs parameter?
Also, if I have an ArrayList<String>, how can I pass that to a varargs method parameter in Kotlin?
Short Answer
By the end of this page, you will understand how Kotlin handles Java varargs, why passing an array directly often fails, and how to use the spread operator (*) to expand a Kotlin array into individual arguments. You will also learn how to convert lists such as ArrayList<String> into arrays before passing them to Java varargs methods.
Concept
In Java, a method with varargs looks like this:
void antMatchers(String... patterns)
Java treats String... as a special syntax for “zero or more String values.” Internally, it is handled as a String[].
When Kotlin calls a Java varargs method, Kotlin does not automatically unpack an Array<String> into separate arguments. Instead, you usually need to explicitly tell Kotlin to spread the array into individual values.
That is what the * spread operator does.
web.ignoring().antMatchers(*angularRoutings)
This matters because Kotlin and Java interoperate closely, but their function call rules are not identical. If you regularly work with Java libraries from Kotlin, especially frameworks like Spring, Android APIs, or older utility libraries, you will often need to pass arrays or collections into Java varargs methods correctly.
For collections like ArrayList<String>, you cannot spread the list directly. A varargs parameter expects individual values, so you must first convert the list to an array:
val routes = arrayListOf("/language", )
web.ignoring().antMatchers(*routes.toTypedArray())
Mental Model
Think of a varargs method like a function that wants several separate items placed on a table:
- Java varargs: “Put each string on the table one by one.”
- Kotlin array: “Here is a box containing strings.”
If you hand over the box directly, the method may not treat it as separate items.
The spread operator * means:
“Open the box and place each item on the table individually.”
If you have a list instead of an array, you first need to pack it into the right kind of box (Array<String>) and then open it with *.
Syntax and Examples
Core syntax
Passing individual values
web.ignoring().antMatchers("/language", "/home")
Passing a Kotlin array to Java varargs
val angularRoutings = arrayOf("/language", "/home")
web.ignoring().antMatchers(*angularRoutings)
Passing an ArrayList<String> or List<String>
val routes = arrayListOf("/language", "/home")
web.ignoring().antMatchers(*routes.toTypedArray())
Why * is needed
Without the spread operator:
val angularRoutings = arrayOf("/language", "/home")
web.ignoring().antMatchers(angularRoutings) // usually does not match the varargs call you expect
With the spread operator:
val angularRoutings = arrayOf(, )
web.ignoring().antMatchers(*angularRoutings)
Step by Step Execution
Consider this example:
val routes = arrayOf("/language", "/home")
web.ignoring().antMatchers(*routes)
Step by step:
arrayOf("/language", "/home")creates a KotlinArray<String>.routesnow holds two strings.antMatchers(...)is a Java method that expects varargs, meaning multipleStringarguments.*routestells Kotlin to spread the array.- Kotlin effectively turns the call into:
web.ignoring().antMatchers("/language", "/home")
- The Java method receives the values as its varargs parameter.
Now compare with a list:
val routes = arrayListOf("/language", "/home")
web.ignoring().antMatchers(*routes.toTypedArray())
Step by step:
arrayListOf(...)creates anArrayList<String>.
Real World Use Cases
This pattern appears often when Kotlin code calls Java libraries.
Common scenarios
- Spring Security: passing URL patterns into methods like
antMatchers(...) - Logging frameworks: passing multiple formatting arguments
- Android APIs: calling Java methods that accept variable numbers of values
- Testing libraries: passing multiple expected values or parameters
- Utility libraries: methods like
of(...),addAll(...), or matcher-style APIs
Example: route configuration
val publicRoutes = arrayOf("/login", "/register", "/about")
web.ignoring().antMatchers(*publicRoutes)
Example: dynamic values from configuration
val configuredRoutes = listOf("/health", "/metrics")
web.ignoring().antMatchers(*configuredRoutes.toTypedArray())
This is useful when the values are not hardcoded and come from files, databases, or application settings.
Real Codebase Usage
In real projects, developers often combine varargs calls with collection building, validation, and configuration.
Common patterns
1. Build a list, then convert once
If your values are dynamic, it is common to collect them in a list and convert at the call site.
val routes = mutableListOf("/home")
if (enableLanguagePage) {
routes.add("/language")
}
web.ignoring().antMatchers(*routes.toTypedArray())
2. Guard against empty collections
val routes = getRoutesFromConfig()
if (routes.isNotEmpty()) {
web.ignoring().antMatchers(*routes.toTypedArray())
}
3. Keep interop code local
A common style is to keep Java interop details near the boundary of the library call.
fun ignoreRoutes(web: WebSecurity, routes: List<String>) {
web.ignoring().antMatchers(*routes.toTypedArray())
}
This keeps the rest of your Kotlin code clean and collection-friendly.
4. Prefer readable data preparation
val publicEndpoints = listOf(
"/login",
,
)
web.ignoring().antMatchers(*publicEndpoints.toTypedArray())
Common Mistakes
1. Forgetting the spread operator
Broken:
val routes = arrayOf("/language", "/home")
web.ignoring().antMatchers(routes)
Fix:
web.ignoring().antMatchers(*routes)
2. Trying to spread a list directly
Broken:
val routes = listOf("/language", "/home")
web.ignoring().antMatchers(*routes)
A List<String> is not an Array<String>.
Fix:
web.ignoring().antMatchers(*routes.toTypedArray())
3. Confusing Java arrays and Kotlin collections
A Kotlin Array<String> and a List<String> are different types with different behaviors.
- Use
Array<String>when you need array-based interop. - Use
List<String>for most regular Kotlin collection work.
4. Assuming varargs always accept collections
Comparisons
Array vs List when calling Java varargs
| Kotlin type | Can be passed directly to Java varargs? | What to do |
|---|---|---|
Array<String> | No, not usually as expanded args | Use *array |
List<String> | No | Convert with toTypedArray() then use * |
ArrayList<String> | No | Convert with toTypedArray() then use * |
| Individual strings | Yes | Pass normally |
Direct arguments vs spread array
Cheat Sheet
// Java method
// void antMatchers(String... patterns)
// Pass direct values
antMatchers("/language", "/home")
// Pass Kotlin array
val routes = arrayOf("/language", "/home")
antMatchers(*routes)
// Pass List or ArrayList
val routes = listOf("/language", "/home")
antMatchers(*routes.toTypedArray())
Rules
- Java
String...becomes a varargs call from Kotlin. - Use
*to spread a Kotlin array into varargs. - You cannot spread a
Listdirectly. - Convert a list with
toTypedArray()first. Array<String>andList<String>are not interchangeable.
Quick fixes
- Have
Array<String>? ->
FAQ
Why does antMatchers(array) fail in Kotlin?
Because Kotlin does not automatically expand the array into separate varargs arguments. Use *array.
How do I pass a Kotlin list to a Java varargs method?
Convert it first: *myList.toTypedArray().
What does the * operator mean in Kotlin?
It is the spread operator. It expands an array into individual arguments for a varargs parameter.
Can I use ArrayList<String> directly with varargs?
No. Convert it to an array first with toTypedArray().
Is Java String... the same as String[]?
Internally, yes. varargs is compiled as an array, but the call syntax is more flexible.
Should I use arrays or lists in Kotlin?
Use lists for most Kotlin code. Use arrays mainly when an API specifically requires them, such as Java varargs interop.
Mini Project
Description
Create a small Kotlin utility that configures public URL routes for a Java-style API that accepts varargs. This demonstrates the exact skill of converting Kotlin arrays and lists into arguments that a Java library can consume.
Goal
Build a function that accepts route values from both an array and a list, then passes them correctly to a varargs-style method.
Requirements
- Create a Kotlin function that simulates a Java varargs method.
- Store route paths in both an
Array<String>and aList<String>. - Pass the array using the spread operator.
- Convert the list to an array before spreading it.
- Print the received routes to confirm the values were passed correctly.
Keep learning
Related questions
Android AlarmManager Example: Scheduling Tasks with AlarmManager
Learn how to use Android AlarmManager to schedule tasks, set alarms, and handle broadcasts with a simple beginner example.
Can You Extend a Data Class in Kotlin? Inheritance, Limits, and Better Alternatives
Learn why Kotlin data classes cannot be extended, what causes the component function clash, and which alternatives to use instead.
Difference Between List and Array in Kotlin
Learn the difference between List and Array in Kotlin, including mutability, size, APIs, performance, and when to use each one.