Kotlin return Keyword
last modified April 19, 2025
The return keyword in Kotlin is fundamental for controlling program
flow. It exits functions and lambda expressions, optionally returning a value.
This tutorial explores return in depth with practical examples.
Basic Definitions
The return keyword terminates function execution and returns control
to the caller. In functions, it can return a value matching the declared return
type. In lambdas, it has special behavior with local and non-local returns.
Basic Function Return
The simplest use of return exits a function and returns a value.
The returned value must match the function's declared return type.
package com.zetcode
fun add(a: Int, b: Int): Int {
return a + b
}
fun main() {
val result = add(5, 7)
println(result) // Output: 12
}
This example shows a basic function with an explicit return. The add
function takes two integers and returns their sum. The return
statement exits the function with the computed value.
Implicit Return in Single-Expression Functions
Kotlin allows omitting the return keyword in single-expression
functions. The expression's result is automatically returned.
package com.zetcode
fun multiply(a: Int, b: Int): Int = a * b
fun main() {
val product = multiply(4, 5)
println(product) // Output: 20
}
Here, the multiply function uses single-expression syntax. The
result of a * b is automatically returned without needing an
explicit return statement. This makes code more concise.
Early Return with Condition
The return statement can exit a function early based on a condition.
This is useful for validation checks or edge cases.
package com.zetcode
fun divide(a: Int, b: Int): Int? {
if (b == 0) return null
return a / b
}
fun main() {
println(divide(10, 2)) // Output: 5
println(divide(10, 0)) // Output: null
}
This function checks for division by zero and returns early if detected. The
return type is nullable Int (Int?) to accommodate the null return
for invalid input. This pattern prevents further execution when conditions fail.
Return from Lambda Expressions
In lambda expressions, return exits the enclosing function by
default (non-local return). To return just from the lambda, use a label.
package com.zetcode
fun processNumbers(numbers: List<Int>, action: (Int) -> Unit) {
numbers.forEach(action)
}
fun main() {
processNumbers(listOf(1, 2, 3, 4)) {
if (it == 3) return@processNumbers // local return
println(it)
}
// Output: 1 2 4
}
This demonstrates labeled return in a lambda. The return@processNumbers
exits only the lambda, not the entire function. Without the label, it would exit
main. Labels control return scope in nested contexts.
Return with Nothing Type
Functions that never return normally (always throw exceptions) can declare
Nothing as their return type. This informs callers about the
behavior.
package com.zetcode
fun fail(message: String): Nothing {
throw IllegalArgumentException(message)
}
fun main() {
val input = readLine()
val number = input?.toIntOrNull() ?: fail("Invalid input")
println("Number is $number")
}
The fail function always throws an exception. Its Nothing
return type tells the compiler execution won't continue normally. This helps with
type inference and makes code intentions clearer.
Return in Anonymous Functions
Anonymous functions behave like regular functions regarding return.
Returns exit the anonymous function itself, unlike in lambdas where they exit
the enclosing function.
package com.zetcode
fun main() {
val numbers = listOf(1, 2, 3, 4, 5)
numbers.forEach(fun(number) {
if (number == 3) return // local to anonymous function
println(number)
})
// Output: 1 2 4 5
}
Here, return exits only the anonymous function, not main.
This differs from lambda behavior. Anonymous functions provide more intuitive
return semantics in some cases compared to labeled returns in lambdas.
Return with Value in Lambdas
Lambda expressions implicitly return their last expression's value. Explicit
return with value requires qualified syntax.
package com.zetcode
fun transform(numbers: List<Int>, transform: (Int) -> Int): List<Int> {
return numbers.map(transform)
}
fun main() {
val result = transform(listOf(1, 2, 3)) {
if (it == 2) return@transform 20 // explicit return with value
it * 10 // implicit return
}
println(result) // Output: [10, 20, 30]
}
This shows both implicit and explicit returns in a lambda. The value 20 is
returned explicitly when the condition matches. Otherwise, the lambda implicitly
returns it * 10. The labeled return provides the value to the
transformation.
Best Practices for Using return
- Prefer implicit returns: Use single-expression functions when possible for cleaner code.
- Use early returns: Validate inputs and edge cases first for better code structure.
- Understand lambda returns: Remember lambdas use non-local returns by default; use labels when needed.
- Consider Nothing: Mark functions that never return normally
with
Nothingreturn type. - Choose anonymous functions: When lambda return behavior is confusing, consider anonymous functions for more intuitive returns.
Source
Kotlin Returns and Jumps Documentation
This tutorial covered Kotlin's return keyword in depth, showing its
use in functions and lambdas. We explored various scenarios including early
returns, labeled returns, and special cases like Nothing. Proper
use of return makes control flow clear and code more maintainable.
Author
List all Kotlin tutorials.