Authors Top

If you have a few years of experience with the Kotlin language and server-side development, and you’re interested in sharing that experience with the community, have a look at our Contribution Guidelines.

1. Overview

In this tutorial, we’ll discuss the usage of structural jump expressions in Kotlin.

Simply put, Kotlin has three structural jump expressions: return, break, continue. In the next sections, we’ll cover their functionalities with and without a label.

2. Labels in Kotlin

Any expressions in Kotlin can be marked with a label.

We create a label by using an identifier followed by the “@” sign. For example, [email protected], [email protected] are valid labels.

To label an expression, we simply add the label in front of it:

[email protected] for (i in 1..10) {
    // some code 
}

3. The Break Statement

Without a label, break terminates the nearest enclosing loop.

Let’s have a look at an example:

@Test
fun givenLoop_whenBreak_thenComplete() {
    var value = ""
    for (i in "hello_world") {
        if (i == '_') break
        value += i.toString()
    }
    assertEquals("hello", value)
}

Alternatively, we can use break with a label, which terminates the loop marked with that label:

@Test
fun givenLoop_whenBreakWithLabel_thenComplete() {
    var value = ""
    [email protected] for (i in 'a'..'d') {
        for (j in 1..3) {
            value += "" + i + j
            if (i == 'b' && j == 1)
                [email protected]_loop
        }
    }
    assertEquals("a1a2a3b1", value)
}

In this case, the outer loop is terminated when the i and j variables equal “b” and “1” respectively.

4. The Continue Statement

Next, let’s have a look at the continue keyword, which we can also use with or without a label.

Without a label, continue will proceed to the next iteration of the enclosing loop:

@Test
fun givenLoop_whenContinue_thenComplete() {
    var result = ""
    for (i in "hello_world") {
        if (i == '_') continue
        result += i
    }
    assertEquals("helloworld", result)
}

On the other hand, when we use continue with a label marking a loop, it will proceed to the next iteration of that loop:

@Test
fun givenLoop_whenContinueWithLabel_thenComplete() {
    var result = ""
    [email protected] for (i in 'a'..'c') {
        for (j in 1..3) {
            if (i == 'b') [email protected]_loop
            result += "" + i + j
        }
    }
    assertEquals("a1a2a3c1c2c3", result)
}

In this example, we’ve used continue to skip one iteration of the loop labeled outer_loop.

5. The Return Statement

Without a label, it returns to the nearest enclosing function or anonymous function:

@Test
fun givenLambda_whenReturn_thenComplete() {
    var result = returnInLambda();
    assertEquals("hello", result)
}

private fun returnInLambda(): String {
    var result = ""
    "hello_world".forEach {
        if (it == '_') return result
        result += it.toString()
    }
    //this line won't be reached
    return result;
}

Return is also useful when we want to apply continue logic on anonymous functions:

@Test
fun givenAnonymousFunction_return_thenComplete() {
    var result = ""
    "hello_world".forEach(fun(element) {
        if (element == '_') return
        result += element.toString()
    })
    assertEquals("helloworld", result)
}

In this example, the return statement will return to the caller of the anonymous fun, i.e. the forEach loop.

In the case of a lambda expression, we can also use return with a label to achieve a similar result:

@Test
fun givenLambda_whenReturnWithExplicitLabel_thenComplete() {
    var result = ""
    "hello_world".forEach [email protected]{
        if (it == '_') {
            [email protected]
        }
        result += it.toString()
    }
    assertEquals("helloworld", result)
}

Alternatively, we can also return using an implicit label:

@Test
fun givenLambda_whenReturnWithImplicitLabel_thenComplete() {
    var result = ""
    "hello_world".forEach {
        if (it == '_') {
            // local return to the caller of the lambda, i.e. the forEach loop
            [email protected]
        }
        result += it.toString()
    }
    assertEquals("helloworld", result)
}

In the example above, the return statement will also return to the caller of the lambda – the forEach loop.

Finally, return can be used with a label to apply break logic to lambda expressions by returning to a label outside:

@Test
fun givenAnonymousFunction_returnToLabel_thenComplete() {
    var result = ""
    run [email protected]{
        "hello_world".forEach {
            if (it == '_') [email protected]
            result += it.toString()
        }
    }
    assertEquals("hello", result)
}

6. Conclusion

In this article, we have gone through the use cases of return, break, continue in Kotlin.

The sample code could be found over on GitHub.

Authors Bottom

If you have a few years of experience with the Kotlin language and server-side development, and you’re interested in sharing that experience with the community, have a look at our Contribution Guidelines.

Comments are closed on this article!