Kotlin Labels
When working with nested loops or blocks of code in Kotlin, there are times when you need more precise control over which loop or block you want to break from or continue to the next iteration. This is where labels come into play.
What Are Labels?
Labels in Kotlin are identifiers followed by the @
symbol that you can place before loops and expressions. They allow you to:
- Break out of specific outer loops from inner loops
- Continue to the next iteration of a specific outer loop
- Return from a specific function or lambda expression
Labels give you more explicit control over your program flow, especially in complex nested structures.
Basic Label Syntax
A label in Kotlin is defined by an identifier followed by the @
sign:
labelName@
You can attach this label to loops, expressions, or functions, and later refer to it with break
, continue
, or return
statements.
Breaking with Labels
Let's see how labels can help us break out of nested loops:
Without Labels
fun main() {
for (i in 1..3) {
for (j in 1..3) {
if (i * j > 4) {
println("Breaking when i=$i and j=$j")
break // This only breaks out of the inner loop
}
println("i=$i, j=$j")
}
}
println("Loop completed")
}
Output:
i=1, j=1
i=1, j=2
i=1, j=3
i=2, j=1
i=2, j=2
Breaking when i=2 and j=3
i=3, j=1
i=3, j=2
Breaking when i=3 and j=2
Loop completed
Notice that the break
statement only breaks out of the innermost loop. If we want to break out of the outer loop, we need labels.
With Labels
fun main() {
outerLoop@ for (i in 1..3) {
for (j in 1..3) {
if (i * j > 4) {
println("Breaking out of outer loop when i=$i and j=$j")
break@outerLoop // This breaks out of the labeled outer loop
}
println("i=$i, j=$j")
}
}
println("Loop completed")
}
Output:
i=1, j=1
i=1, j=2
i=1, j=3
i=2, j=1
i=2, j=2
Breaking out of outer loop when i=2 and j=3
Loop completed
The break@outerLoop
statement breaks out of the entire outer loop when the condition i * j > 4
is met.
Continue with Labels
Similarly, we can use labels with the continue
keyword:
fun main() {
outerLoop@ for (i in 1..3) {
for (j in 1..3) {
if (j == 2) {
println("Skipping to next i when j=2")
continue@outerLoop // Skip to the next iteration of the outer loop
}
println("i=$i, j=$j")
}
}
println("Loop completed")
}
Output:
i=1, j=1
Skipping to next i when j=2
i=2, j=1
Skipping to next i when j=2
i=3, j=1
Skipping to next i when j=2
Loop completed
Here, continue@outerLoop
skips the current iteration of the outer loop entirely, moving to the next value of i
.
Return with Labels
Labels can also be used with return
statements, particularly in lambda expressions:
fun main() {
val numbers = listOf(1, 2, 3, 4, 5)
numbers.forEach labelName@ {
if (it == 3) {
println("Found 3, skipping this item")
return@labelName // Return from the lambda for this item only
}
println("Processing number: $it")
}
println("All numbers processed")
}
Output:
Processing number: 1
Processing number: 2
Found 3, skipping this item
Processing number: 4
Processing number: 5
All numbers processed
Without the label, a regular return
would exit the entire main
function. With the label, we only exit the current iteration of the lambda.
Implicit Labels for Lambdas
Kotlin provides implicit labels for lambda expressions, which are the same as the function name:
fun main() {
val numbers = listOf(1, 2, 3, 4, 5)
numbers.forEach {
if (it == 3) return@forEach // Implicit label, same as the function name
println("Processing number: $it")
}
println("All numbers processed")
}
Output:
Processing number: 1
Processing number: 2
Processing number: 4
Processing number: 5
All numbers processed
Real-World Applications
1. Searching in Multi-dimensional Arrays
fun findElement(matrix: Array<Array<Int>>, target: Int): Pair<Int, Int>? {
search@ for (i in matrix.indices) {
for (j in matrix[i].indices) {
if (matrix[i][j] == target) {
return Pair(i, j)
}
}
}
return null // Element not found
}
fun main() {
val matrix = arrayOf(
arrayOf(1, 2, 3),
arrayOf(4, 5, 6),
arrayOf(7, 8, 9)
)
val result = findElement(matrix, 5)
if (result != null) {
println("Element found at position (${result.first}, ${result.second})")
} else {
println("Element not found")
}
}
Output:
Element found at position (1, 1)
2. Processing Nested Collections
fun processNestedLists(lists: List<List<String>>) {
outerLoop@ for (innerList in lists) {
// Skip empty lists
if (innerList.isEmpty()) {
println("Skipping empty list")
continue@outerLoop
}
for (item in innerList) {
// Stop processing all lists if we find "stop"
if (item == "stop") {
println("Found stop command, exiting entirely")
break@outerLoop
}
println("Processing item: $item")
}
}
}
fun main() {
val nestedLists = listOf(
listOf("apple", "banana"),
listOf(),
listOf("cherry", "stop", "grape"),
listOf("kiwi", "mango")
)
processNestedLists(nestedLists)
}
Output:
Processing item: apple
Processing item: banana
Skipping empty list
Processing item: cherry
Found stop command, exiting entirely
Best Practices for Using Labels
- Use sparingly - Labels can make code harder to read if overused
- Choose descriptive names - Make your labels clear about what they refer to
- Comment your labels - Especially for complex nested structures
- Consider refactoring - If you find yourself using many labels, it might be a sign to break down your code into smaller functions
Summary
Labels in Kotlin provide a powerful way to control program flow, especially in nested structures:
- They allow you to break or continue specific loops in nested loop structures
- They enable you to return from specific lambda expressions without exiting the entire function
- They can make your code clearer when handling complex control flow
While labels are powerful, they should be used judiciously. In many cases, extracting methods or using other control flow techniques might lead to more readable code.
Exercises
- Write a program that uses labels to print only the numbers in a 3x3 matrix that are less than 5.
- Create a nested structure with three loops and use labels to break out of all loops when a specific condition is met.
- Write a function that uses labels with lambda expressions to filter and transform a list of strings.
Additional Resources
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)