`break` and `continue` in `forEach` in Kotlin
Solution 1:
This will print 1 to 5. The return@forEach
acts like the keyword continue
in Java, which means in this case, it still executes every loop but skips to the next iteration if the value is greater than 5.
fun main(args: Array<String>) {
val nums = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
nums.forEach {
if (it > 5) return@forEach
println(it)
}
}
This will print 1 to 10 but skips 5.
fun main(args: Array<String>) {
val nums = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
nums.forEach {
if (it == 5) return@forEach
println(it)
}
}
Try them at Kotlin Playground.
Solution 2:
Edit:
According to Kotlin's documentation, it is possible to simulate continue
using annotations.
fun foo() {
listOf(1, 2, 3, 4, 5).forEach lit@ {
if (it == 3) return@lit // local return to the caller of the lambda, i.e. the forEach loop
print(it)
}
print(" done with explicit label")
}
If you want to simulate a break
, just add a run
block
fun foo() {
run lit@ {
listOf(1, 2, 3, 4, 5).forEach {
if (it == 3) return@lit // local return to the caller of the lambda, i.e. the forEach loop
print(it)
}
print(" done with explicit label")
}
}
Original Answer:
Since you supply a (Int) -> Unit
, you can't break from it, since the compiler do not know that it is used in a loop.
You have few options:
Use a regular for loop:
for (index in 0 until times) {
// your code here
}
If the loop is the last code in the method
you can use return
to get out of the method (or return value
if it is not unit
method).
Use a method
Create a custom repeat method method that returns Boolean
for continuing.
public inline fun repeatUntil(times: Int, body: (Int) -> Boolean) {
for (index in 0 until times) {
if (!body(index)) break
}
}
Solution 3:
A break can be achieved using:
//Will produce "12 done with nested loop"
//Using "run" and a tag will prevent the loop from running again.
//Using return@forEach if I>=3 may look simpler, but it will keep running the loop and checking if i>=3 for values >=3 which is a waste of time.
fun foo() {
run loop@{
listOf(1, 2, 3, 4, 5).forEach {
if (it == 3) return@loop // non-local return from the lambda passed to run
print(it)
}
}
print(" done with nested loop")
}
And a continue can be achieved with:
//Will produce: "1245 done with implicit label"
fun foo() {
listOf(1, 2, 3, 4, 5).forEach {
if (it == 3) return@forEach // local return to the caller of the lambda, i.e. the forEach loop
print(it)
}
print(" done with implicit label")
}
As anyone here recommends... read the docs :P https://kotlinlang.org/docs/reference/returns.html#return-at-labels
EDIT: While the main question asks about forEach, it's important to consider the the good old "for". Using Kotlin doesn't mean we need to use forEach all the time. Using the good old "for" is perfectly ok, and sometimes even more expressive and concise than forEach:
fun foo() {
for(x in listOf(1, 2, 3, 4, 5){
if (x == 3) break //or continue
print(x)
}
print("done with the good old for")
}
Solution 4:
You can use return from lambda expression which mimics a continue
or break
depending on your usage.
This is covered in the related question: How do I do a "break" or "continue" when in a functional loop within Kotlin?