1. Introduction
In this article, we’ll show how the break statement is used in Scala to terminate loops.
The break statement can stop for, while, and do…while loops.
2. Under the Hood
Since the break statement in Scala isn’t a language feature but just an implemented method, it has no context of the corresponding loops.
The way that the break statement works is by throwing an exception. Let’s look at the breakable function implementation:
def breakable(op: => Unit) {
try {
op
} catch {
case ex: BreakControl =>
if (ex ne breakException) throw ex
}
}
As a result of the breakable implementation, the exception that is thrown by the break function is ignored but the loop stops:
def break(): Nothing = { throw breakException }
This is crucial for the understanding of how this statement works, especially for cases of multiple loops.
3. Simple Loops
Let’s write a simple for loop and use the break statement to terminate it:
breakable {
for (i <- Range(0, 10)) yield {
if (i > 3) {
break()
}
println(s"$i * 2 = ${i * 2}")
}
}
We’ll get the console output:
0 * 2 = 0
1 * 2 = 2
2 * 2 = 4
3 * 2 = 6
Alternatively, we can write the above with an instance of the Breaks class:
val loop = new Breaks
loop.breakable {
for (i <- Range(0, 10)) yield {
if (i > 3) {
break()
}
println(i * 2)
}
}
4. Nested Loops
Now, let’s consider a more complicated scenario with more than one loop.
Here, we use a single break statement for both loops:
var i = 0
breakable {
while (i < 4) {
var j = 1
while (j < 3) {
if (i == 3) {
break()
}
println(s"i: $i, j: $j")
j += 1
}
i += 1
}
}
Running this snippet will output on the console:
i: 0, j: 1
i: 0, j: 2
i: 1, j: 1
i: 1, j: 2
i: 2, j: 1
i: 2, j: 2
Now, let’s take a more refined approach and break from the loops individually:
var i = 0
val outerLoop = new Breaks
outerLoop.breakable {
while (i < 4) {
if (i == 3) {
outerLoop.break()
}
var j = 2
val innerLoop = new Breaks
innerLoop.breakable {
while (j < 6) {
if (j == 5) {
innerLoop.break()
}
println(s"i: $i, j: $j")
j += 1
}
}
i += 1
}
}
Let’s check the console output:
i: 0, j: 2
i: 0, j: 3
i: 0, j: 4
i: 1, j: 2
i: 1, j: 3
i: 1, j: 4
i: 2, j: 2
i: 2, j: 3
i: 2, j: 4
5. Try Variation
Additionally, the Breaks class provides the tryBreakable function. As the name implies, this function allows us to handle the cases where the break function is called:
tryBreakable[Unit] {
for (i <- Range(0, 10)) yield {
if (i > 3) {
break()
}
println(s"$i * 2 = ${i * 2}")
}
} catchBreak {
println("break called!")
}
When we run this code, we’ll see the console output:
0 * 2 = 0
1 * 2 = 2
2 * 2 = 4
3 * 2 = 6
break called!
6. Conclusion
In this article, we presented the break statement and the utility functions of the Breaks class as a way for terminating loops. While this is a non-functional way of handling data structures, there are cases where it can be useful. When in doubt about which loop to choose, check our Loops in Functional Scala article.
As always, the code of the above examples is available over on GitHub.