相关文章推荐
可爱的小蝌蚪  ·  1,win10 ...·  6 月前    · 
酒量大的烈酒  ·  .NET Source ...·  9 月前    · 
玩篮球的红豆  ·  python - ...·  1 年前    · 
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

Kotlin has very nice iterating functions, like forEach or repeat , but I am not able to make the break and continue operators work with them (both local and non-local):

repeat(5) {
    break
(1..5).forEach {
    continue@forEach

The goal is to mimic usual loops with the functional syntax as close as it might be. It was definitely possible in some older versions of Kotlin, but I struggle to reproduce the syntax.

The problem might be a bug with labels (M12), but I think that the first example should work anyway.

It seems to me that I've read somewhere about a special trick/annotation, but I could not find any reference on the subject. Might look like the following:

public inline fun repeat(times: Int, @loop body: (Int) -> Unit) {
    for (index in 0..times - 1) {
        body(index)
                In current Kotlin you can indeed mimic this (while waiting for the continue@label and break@label features), see related question: stackoverflow.com/questions/34642868/…
– Jayson Minard
                Jan 6, 2016 at 21:14
                This question could use clarification about whether you are asking only about the existance of break and continue for functional loops, or if you are seeking alternative answers that do exactly the same thing.  The former appears to be the case, because you rejected the latter.
– Jayson Minard
                Jan 6, 2016 at 21:17

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)

This will print 1 to 4, and break when reaching 5.

fun main(args: Array<String>) {
    val nums = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
    run breaking@ {
        nums.forEach {
           if (it == 5) return@breaking
           println(it)

Link to code snippet from ashuges.

Great, but this still doesn't address the problem of not being able to end the forEach prematurely when some condition is met. It still keeps on executing the loop. – The Fox Oct 20, 2019 at 13:30 @TheFox yes, it executes every loop and anything after the return is skipped when condition is met. Each operation in the forEach is a lambda function, currently there is no exact break operation for the forEach operation. The break is available in for loops, see: kotlinlang.org/docs/reference/returns.html – s-hunter Oct 28, 2019 at 11:32 Here's a runnable Kotlin Playground snippet with both a continue and break example: pl.kotl.in/_LAvET-wX – ashughes Jun 30, 2020 at 23:03

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
                Actually, my question was about making the specific syntax work, not about iterating. Don't you remember that it was possible at some Kotlin milestone?
– voddan
                Sep 13, 2015 at 10:11
                I don't remember. But maybe it is because I don't use break & continue a lot. See this issue, it says "Estimation - No estimation".
– Yoav Sternberg
                Sep 13, 2015 at 11:43
                break and continue only work in loops. forEach, repeat and all the other methods are just that: methods and not loops. Yoav presented some alternatives but break and continue are just not ment to work for methods.
– Kirill Rakhman
                Sep 13, 2015 at 12:44
                @YoavSternberg Brilliant! This peace of old docs is what I was looking for! So the feature is not implemented yet, left for future versions. If you care to create a separate answer, I'll mark it
– voddan
                Sep 14, 2015 at 8:16
                In current Kotlin you can indeed mimic this (while waiting for the continue@label and break@label features), see related question: stackoverflow.com/questions/34642868/…
– Jayson Minard
                Jan 6, 2016 at 21:14

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")
                Nice solution. Works very well. Though it seems like without using @loop gives the same desired result as well.
– Paras Sidhu
                Jun 17, 2020 at 5:30
                In fact, you can omit the explicit tag "@loop" and use the implicit one "@run". The key aspect here is the local return to the caller of the lambda. Note you need to wrap the loop inside some scope so you can local return on it  later on.
– Raymond Arteaga
                Jun 17, 2020 at 23:26
                This really answers the question, however i think this probably isn't the right path to take for functional programming. What we need is, from Lodash, transform where you can break under certain condition, ex. reduceReturnIf(acc, value, returnIf: func)
– windmaomao
                Aug 15, 2020 at 17:54

As the Kotlin documentation says, using return is the way to go. Good thing about Kotlin is that if you have nested functions, you can use labels to explicitly write where your return is from:

Function Scope Return
fun foo() {
    listOf(1, 2, 3, 4, 5).forEach {
        /** Non-local return directly to the caller of foo(). */
        if (it == 3) return
        print(it)
    println("this point is unreachable")
Local Return

It doesn't stop going through forEach loop (it's like a continue in for loop).

fun foo() {
    listOf(1, 2, 3, 4, 5).forEach lit@{
        /** Local return to the caller of the lambda, i.e. the forEach loop. */
        if (it == 3) return@lit
        print(it)
    print(" done with explicit label")

Check out the documentation, it's really good :)

That is correct. It's intended. The first solution it does, but if you have instructions inside a loop you can choose where do you want to return to / jump to. In the second case, if we just use return it will stop ;-) – cesards Dec 12, 2018 at 15:44

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?

continue type behaviour in forEach

list.forEach { item -> // here forEach give you data item and you can use it 
    if () {
        // your code
        return@forEach // Same as continue
    // your code

for break type behaviour you have to use for in until or for in as per the list is Nullable or Non-Nullable

  • For Nullable list:

    for (index in 0 until list.size) {
        val item = list[index] // you can use data item now
        if () {
            // your code
            break
        // your code
    
  • For Non-Nullable list:

    for (item in list) { // data item will available right away
        if () {
            // your code
            break
        // your code
    

    I have the perfect solution for this (:

    list.apply{ forEach{ item ->
        if (willContinue(item)) return@forEach
        if (willBreak(item)) return@apply
    
    listOf("a", "b", "c").forEach find@{ i ->
        listOf("b", "d").forEach { j ->
            if (i == j) return@find
            println("i = $i, j = $j")
    

    Result:

    i = a, j = b
    i = a, j = d
    i = c, j = b
    i = c, j = d
    

    Continue statement with anonymous function:

    listOf(1, 2, 3, 4, 5).forEach(fun(value: Int) {
        if (value == 3) return
        print("$value ")
    

    Result:

    1 2 4 5 
                    Unfortunately this is the only truly general solution.  The other answers only work in certain cases.
    – SMBiggs
                    Mar 23, 2022 at 19:26
    

    If the condition depends on the outcome of a previous element in the list, you can use sequence and takeWhile to execute depth-first lazily.

    sequenceOf(1, 2, 3, 4, 5).map { i ->
        println("i = ${i}")
    }.takeWhile { success ->
        println("success = ${success}")
        success
    }.toList()
    

    will print

    i = 1
    success = true
    i = 2
    success = true
    i = 3
    success = false
    

    You need the terminal toList() in the end to execute the sequence.

    More details: https://kotlinlang.org/docs/sequences.html#sequence

    fun part2(ops: List<Int>): Int = ops.asSequence()
        .scan(0) { acc, v -> acc + v }
        .indexOf(-1)
    

    If you can afford to turn a collection into a sequence, normally the cost is trivial, then you should be able to take advantage of the deferred feature.

    You might already notice asSequence in the above. It's here for saving us going over the entire list. Right after we have a match via indexOf, it'll stop. Bingo! Saving us write a while here.

    as in Part 2 of medium article.

    Thanks for contributing an answer to Stack Overflow!

    • Please be sure to answer the question. Provide details and share your research!

    But avoid

    • Asking for help, clarification, or responding to other answers.
    • Making statements based on opinion; back them up with references or personal experience.

    To learn more, see our tips on writing great answers.

  •