Functions
|
This section documents Kotlin 2.4.x on the JVM, as published at kotlinlang.org, which is the reference these pages are written and verified against. This content was generated with the assistance of AI and should be verified against kotlinlang.org before being relied on in production. This section’s bibliography lists the reference material consulted while preparing these pages. |
Functions are top-level citizens in Kotlin — a function need not belong to a class (see Lexical Structure and Style) — and Kotlin adds several conveniences over Java’s method declarations that eliminate common sources of boilerplate.
Function Declarations
fun add(a: Int, b: Int): Int {
return a + b
}
fun greet(name: String) { // no return type: implicitly Unit (see Basic Types and Variables)
println("Hello, $name!")
}
Default and Named Arguments
A parameter can declare a default value, letting callers omit it — eliminating most of the reason Java code resorts to overloaded methods:
fun createUser(name: String, isAdmin: Boolean = false, retries: Int = 3) { /* ... */ }
createUser("Ada") // isAdmin=false, retries=3
createUser("Grace", isAdmin = true) // named argument -- skips "retries", order-independent
createUser(name = "Bo", retries = 5, isAdmin = true) // named arguments may appear in any order
Named arguments (isAdmin = true) can be combined with positional ones (positional arguments must come
first) and are especially valuable at a call site with several Boolean/numeric parameters, where positional
-only Java code is easy to misread (createUser("Ada", true, 5) — true/5 meaning what, exactly?).
Single-Expression Functions
A function whose body is one expression can drop the braces and return, using = instead:
fun square(x: Int): Int = x * x
fun isEven(n: Int) = n % 2 == 0 // return type inferred as Boolean
This form is used throughout this section wherever a function body is a single expression — it is not a
separate feature so much as the natural consequence of if/when already being expressions
(Control Flow).
vararg
A parameter marked vararg accepts zero or more arguments, collected as an Array inside the function — Kotlin’s equivalent of Java’s …:
fun sum(vararg numbers: Int): Int = numbers.sum()
sum(1, 2, 3) // 6
sum() // 0
val values = intArrayOf(4, 5, 6)
sum(*values) // the "spread" operator (*) expands an array into vararg positions
Only one parameter may be vararg, and by convention it is placed last (a later positional parameter is then
allowed only via named-argument syntax).
Local Functions
A function may be declared inside another function, nesting arbitrarily and closing over the enclosing function’s local variables — useful for a small helper that has no reason to be visible outside its caller:
fun printFactorial(n: Int) {
fun factorial(x: Int): Int = // local function, only visible inside printFactorial
if (x <= 1) 1 else x * factorial(x - 1)
println("$n! = ${factorial(n)}")
}
tailrec
Marking a recursive function tailrec tells the compiler to rewrite a tail-recursive call (the recursive call
is the very last operation performed) into an equivalent loop, avoiding both the call-stack growth and the
StackOverflowError risk that plain recursion carries for large inputs:
tailrec fun factorial(n: Long, accumulator: Long = 1): Long =
if (n <= 1) accumulator else factorial(n - 1, n * accumulator)
factorial(20) // compiled as an iterative loop, not a deep call chain
The compiler verifies the function actually is in tail form and emits a warning (not silently ignoring the annotation) if it is not.
See Also
-
Lambdas and Higher-Order Functions — functions as values, and passing a function as a parameter.
-
Extension Functions and Scope Functions — functions declared as if they were members of an existing type.
-
Generics and Variance — generic function declarations and
reifiedtype parameters.