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.