Return with Labels
In this page:
Non-Local Return from a Lambda
A plain return inside a lambda passed to an inline function like forEach does not just skip that one iteration -- it exits the entire enclosing function immediately.
Example: Non-Local Return from a Lambda
fun findFirstEven(numbers: List<Int>): Int? {
numbers.forEach {
if (it % 2 == 0) return it
}
return null
}
fun main() {
println("First even: ${findFirstEven(listOf(1, 3, 4, 5))}")
}
Login to try C/C++/Java/PHP code in the editor
Returning from the Lambda Only
Using the implicit label named after the function the lambda is passed to, such as return@forEach, returns from just that single lambda invocation and lets the loop continue with the next item.
Example: Returning from the Lambda Only
fun main() {
val numbers = listOf(1, 2, 3, 4, 5)
numbers.forEach {
if (it % 2 == 0) return@forEach
println("Odd: $it")
}
}
Login to try C/C++/Java/PHP code in the editor
Explicit Labels on a Lambda
You can also define your own explicit label before a lambda, like myLoop@ { ... }, and return from it specifically using return@myLoop.
Example: Explicit Labels on a Lambda
fun main() {
val numbers = listOf(1, 2, 3, 4, 5)
numbers.forEach myLoop@{
if (it == 3) return@myLoop
println("Value: $it")
}
}
Login to try C/C++/Java/PHP code in the editor
Choosing Local vs Non-Local Return
Deciding whether a return inside a lambda should exit the whole function or just that lambda invocation is a deliberate choice -- use the labeled form whenever only the lambda should stop.
Example: Choosing Local vs Non-Local Return
fun processAll(numbers: List<Int>) {
for (n in numbers) {
numbers.forEach {
if (it == n) return@forEach
println("Comparing $n with $it")
}
}
}
fun main() {
processAll(listOf(1, 2))
}
Login to try C/C++/Java/PHP code in the editor
- Assuming a plain
returninside a lambda passed toforEachexits only that lambda, when it actually returns from the enclosing function (a non-local return). - Forgetting to label the return when only the lambda itself should stop, resulting in the surrounding function exiting unexpectedly early.
- Using implicit labels (named after the function, like
forEach$0) instead of the clearer explicit label syntax when precision matters.
- A plain
returninside a lambda passed to an inline function performs a non-local return, exiting the enclosing function entirely. - Labeling a lambda with
name@ { ... }and usingreturn@namereturns from just that lambda, not the whole function. - Kotlin also provides an implicit label matching the name of the function the lambda is passed to, such as
return@forEach. - Choosing the right kind of return (local vs non-local) avoids surprising control-flow bugs in loops built from higher-order functions.
Chapter Quiz — Complete all 7 topics to unlock
0/7 topics done
Complete these topics first: