Simplify Loops with Non-Local break and continue in Kotlin 2.1.0

Kotlin 2.1 introduced non-local break and continue, a feature that enhances loop control in higher-order functions like forEach. If you've ever struggled with nested loops or found yourself wishing for cleaner ways to exit or skip iterations in higher-order functions, this feature is here to save the day.

In this blog, we’ll dive deep into what this feature is, why it matters, and how you can use it effectively in your Kotlin projects.

What Are Non-Local break and continue?

When working with higher-order functions like forEach, you might have noticed a limitation: there was no direct way to use break or continue. You had to rely on awkward workarounds, like adding return statements or using labeled loops.

With Kotlin 2.1, non-local break and continue allow you to:

  • Exit a loop (break)

  • Skip an iteration (continue)
    …directly from a higher-order function, just as you would in a regular loop!

This feature makes your code cleaner, more expressive, and easier to maintain.

Before Kotlin 2.1: The Android Struggle

Let’s say you’re iterating over a list of strings to filter valid user inputs:

val inputs = listOf("valid_input", "invalid", "valid_input_2", "stop_here")

inputs.forEach { input ->
    if (input == "invalid") return@forEach  // Skip invalid inputs
    if (input == "stop_here") return  // Exit the loop
    Log.d("InputProcessing", "Processing: $input")
}
Log.d("InputProcessing", "Done!")

Here, return@forEach skips invalid inputs, but to break the loop entirely, you need workarounds like returning from the enclosing function. This can make the code harder to read and maintain.

After Kotlin 2.1: Clean and Intuitive

With non-local break and continue, Android developers can now write clear and concise code:

val inputs = listOf("valid_input", "invalid", "valid_input_2", "stop_here")

inputs.forEach { input ->
    if (input == "invalid") continue  // Skip invalid inputs
    if (input == "stop_here") break  // Exit the loop
    Log.d("InputProcessing", "Processing: $input")
}
Log.d("InputProcessing", "Done!")

Output

D/InputProcessing: Processing: valid_input  
D/InputProcessing: Processing: valid_input_2  
D/InputProcessing: Done!

How It Works

Non-Local continue

You can use continue inside higher-order functions to skip the current iteration of the loop:

val words = listOf("apple", "banana", "cherry", "date")

words.forEach { word ->
    if (word.startsWith("b")) continue
    println(word)
}

Output

apple  
cherry  
date

Non-Local break

You can use break to exit the loop entirely, even when using forEach:

val words = listOf("apple", "banana", "cherry", "date")

words.forEach { word ->
    if (word.startsWith("c")) break
    println(word)
}

Output

apple  
banana

Where Can You Use It?

Non-local break and continue work seamlessly in Kotlin 2.1 in all inline higher-order functions. This includes functions like:

  • forEach

  • map

  • filter

However, they cannot be used in non-inline functions, as these do not support the required inlining for non-local control flow.

Examples in Action

Let’s explore some practical use cases:

Example 1: Processing Files

Suppose you’re reading a list of filenames and want to stop at the first invalid file:

val files = listOf("file1.txt", "file2.txt", "invalid_file", "file3.txt")

files.forEach { file ->
    if (file.contains("invalid")) break
    println("Processing $file")
}

Output

Processing file1.txt  
Processing file2.txt

Example 2: Skipping Specific Items

You’re iterating over a list of items, but you want to skip items that match a certain condition:

val numbers = listOf(10, 20, 30, 40, 50)

numbers.forEach { number ->
    if (number % 20 == 0) continue
    println(number)
}

Output

10  
30  
50

Example 3: Breaking Out of a Nested Loop

Non-local break can be a lifesaver when working with nested loops:

val matrix = listOf(
    listOf(1, 2, 3),
    listOf(4, 5, 6),
    listOf(7, 8, 9)
)

matrix.forEach { row ->
    row.forEach { value ->
        if (value == 5) break
        println(value)
    }
    println("Finished row")  // This won't print for rows after the break
}

Output

1  
2  
3  
4  
Finished row

Conclusion

Kotlin 2.1’s non-local break and continue simplify working with loops inside higher-order functions. Whether you’re iterating over collections or processing data, this feature makes your code more concise, intuitive, and readable.

If you haven’t already upgraded to Kotlin 2.1, now is the perfect time to do so and start leveraging these improvements.


Akshay Nandwana
Founder AndroidEngineers

You can connect with me on:


Book 1:1 Session here
Click Here

Join our upcoming classes
https://www.androidengineers.in/courses

Love from our past students

Excellent list of questions really helped me to coverup all the topics before interview.

Saiteja Janjirala

10th Oct, 2024

I had an exceptional experience with the 1:1 mentorship session. Akshay was incredibly friendly and provided invaluable guidance on focusing on long-term goals. They also gave great interview tips, including a thorough resume review. Additionally, the discussion on Data Structures and Algorithms (DSA) was insightful and practical. Highly recommended for anyone looking to advance their career!

Nayab khan

11th Sep, 2024

Cleared my major points for what I am missing in the resume and also suggested what I can work on for further growth in the career.

Ketan Chaurasiya

7th Aug, 2024

What impressed me most was his personalized approach and practical tips that I could immediately apply. Akshay’s guidance not only improved my technical skills but also boosted my confidence in navigating my career path. His insights and encouragement have been a game-changer for me. I highly recommend Akshay’s mentorship to anyone looking to advance their Android development career.

Hardik Kubavat

5th Aug, 2024

2025© Made with   by Android Engineers.