Question
In Kotlin, iteration helpers such as forEach and repeat are convenient, but break and continue do not seem to work with them the same way they do in normal loops.
For example:
repeat(5) {
break
}
(1..5).forEach {
continue@forEach
}
How can you achieve behavior similar to break and continue when using Kotlin's functional iteration style?
I want to mimic ordinary loops as closely as possible while still using functions like forEach and repeat. I believe this may have worked differently in older Kotlin versions, or there may be a special language feature or annotation involved.
For example, I was expecting something like this to be possible:
public inline fun repeat(times: Int, body: (Int) -> Unit) {
for (index in 0 until times) {
body(index)
}
}
Why does this happen, and what is the correct Kotlin approach?
Short Answer
By the end of this page, you will understand why break and continue do not work directly inside Kotlin functions like forEach and repeat, how inline functions and labeled return behave, and when to use a regular for loop instead. You will also learn practical alternatives for skipping items, stopping iteration early, and writing clear loop logic in real Kotlin code.
Concept
In Kotlin, break and continue are loop-control keywords. They only work with actual loop constructs such as:
forwhiledo...while
Functions like forEach and repeat may look like loops when you read them, but they are still function calls. Their bodies are lambdas, not loop bodies in the language grammar.
That difference matters:
breakmeans: stop the nearest real loop.continuemeans: skip to the next iteration of the nearest real loop.- A lambda passed to
forEachis not itself a loop.
So this does not work:
(1..5).forEach {
break
}
because break can only target a real loop.
What can you do instead?
Kotlin gives you a useful alternative: returns from lambdas.
-like behavior
Mental Model
Think of a regular loop as a treadmill with built-in control buttons:
continue= skip this step and move to the next onebreak= stop the treadmill completely
Now think of forEach as hiring a worker to process each item one at a time. You can tell the worker, “stop what you're doing for this item” using return@forEach, but that is not the same as pressing the treadmill's break button. The worker is just inside a function call, not controlling the actual loop keyword machinery.
So:
- Real loop = you control the loop directly
forEachlambda = you control only the current callback execution
That is why return@forEach feels like continue, but there is no direct equivalent of break there.
Syntax and Examples
Real loop syntax
for (i in 1..5) {
if (i == 2) continue
if (i == 4) break
println(i)
}
forEach with continue-like behavior
Use a labeled return:
(1..5).forEach {
if (it == 3) return@forEach
println(it)
}
Explanation
- When
it == 3,return@forEachends the current lambda call. forEachthen moves on to the next item.- This is the closest equivalent to
continue.
forEach cannot use break
This is invalid:
Step by Step Execution
Consider this example:
(1..5).forEach {
if (it == 3) return@forEach
println(it)
}
Step-by-step
1..5creates a range:1, 2, 3, 4, 5forEachstarts calling the lambda for each value.- First value:
it = 1it == 3is falseprintln(1)runs
- Second value:
it = 2it == 3is falseprintln(2)runs
- Third value:
it = 3it == 3is truereturn@forEachexits the lambda for this itemprintln(it)is skipped
- Fourth value:
it = 4
Real World Use Cases
Skipping invalid data during processing
val names = listOf("Ana", "", "Ben")
names.forEach {
if (it.isBlank()) return@forEach
println(it)
}
Useful when processing user input or CSV rows.
Searching until a match is found
Instead of forcing break into forEach, use a search function:
val userId = listOf(10, 20, 30).firstOrNull { it == 20 }
This is common in APIs and database result handling.
Validating a list of items
val allPositive = listOf(1, 2, 3).all { it > 0 }
This often replaces manual loops that would break on failure.
Processing items until a condition changes
val values = listOf(1, , , , , )
values.takeWhile { it != }.forEach { println(it) }
Real Codebase Usage
In real Kotlin projects, developers usually choose iteration style based on intent.
Common patterns
1. Use forEach for side effects on every item
users.forEach { println(it.name) }
This is good when you simply want to do something for each element.
2. Use return@forEach as a guard clause
users.forEach {
if (!it.isActive) return@forEach
sendEmail(it)
}
This is a common pattern for skipping invalid or irrelevant items.
3. Use filter before forEach
users
.filter { it.isActive }
.forEach { sendEmail(it) }
This often reads better than putting skip logic inside forEach.
4. Use firstOrNull, find, any, or all instead of manual early exit
Common Mistakes
Mistake 1: Trying to use break inside forEach
Broken code:
(1..5).forEach {
if (it == 3) break
}
Why it fails:
breakonly works in real loops.forEachis a function call with a lambda.
How to fix it:
- Use a
forloop, or - use a function that matches your intent, such as
findortakeWhile
Mistake 2: Expecting return@forEach to stop everything
Broken expectation:
(1..5).forEach {
if (it == 3) return@forEach
println(it)
}
Some beginners expect the loop to stop at 3, but it does not. It only skips that one element.
Comparisons
| Concept | Works with break | Works with continue | Best for |
|---|---|---|---|
for loop | Yes | Yes | Classic loop control |
while loop | Yes | Yes | Condition-based repetition |
forEach | No | No direct keyword, but return@forEach is similar | Side effects for each item |
repeat | No | No direct keyword, but return@repeat is similar | Fixed-count repetition |
Cheat Sheet
Quick rules
breakworks only in real loops:for,while,do...whilecontinueworks only in real loopsforEachandrepeatare functions, not loop keywordsreturn@forEachskips the current lambda callreturn@repeatskips the current lambda call- Use
forwhen you need truebreakorcontinue
Common patterns
Skip current item in forEach
items.forEach {
if (shouldSkip(it)) return@forEach
process(it)
}
Stop early when searching
val match = items.firstOrNull { condition(it) }
Stop processing while condition is true
FAQ
Can I use break inside forEach in Kotlin?
No. break only works with actual loop statements like for and while, not inside lambdas passed to functions.
How do I simulate continue in Kotlin forEach?
Use a labeled return:
return@forEach
This skips the rest of the current lambda execution.
How do I stop a forEach early in Kotlin?
Usually, you should use a for loop instead. If your goal is searching or checking a condition, use functions like find, firstOrNull, any, or takeWhile.
Does inline allow break and continue inside lambdas?
Mini Project
Description
Build a small Kotlin program that processes a list of numbers and demonstrates when to use forEach with return@forEach and when to switch to a normal for loop. This project helps you see the practical difference between skipping the current item and stopping iteration entirely.
Goal
Create a program that skips negative numbers, prints valid numbers, and stops completely when a special stop value is found.
Requirements
- Create a list of integers containing positive numbers, negative numbers, and a stop value such as
0. - Use
forEachonce to print only non-negative numbers by skipping negatives. - Use a normal
forloop once to stop processing when the stop value is reached. - Print clear labels so the output shows the difference between the two approaches.
Keep learning
Related questions
Accessing Kotlin Extension Functions from Java
Learn how Kotlin extension functions are compiled and how to call them correctly from Java with clear examples and common pitfalls.
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.
Android Foreground Service Notification Channels in Kotlin
Learn why startForeground fails on Android 8.1 and how to create a valid notification channel for foreground services in Kotlin.