# break & continue

break and continue allow you to “jump” within a loop.

Early programmers wrote directly to the processor, using either numerical opcodes as instructions, or assembly language, which translates into opcodes. This kind of programming is as low-level as you can get. For example, many coding decisions were facilitated by “jumping” directly to other places in the code. Early higher-level languages (including FORTRAN, ALGOL, Pascal, C and C++) duplicated this practice by implementing a goto keyword.

goto made assembly-language programmers more comfortable as they transitioned to higher-level languages. As we accumulated more experience, however, the programming community discovered that unconditional jumps produce complicated and un-maintainable code. This generated a large backlash against goto, and most subsequent languages have avoided any kind of unconditional jump.

Kotlin provides a constrained jump in the form of break and continue. These are tied to the looping constructs for, while and do-while—you can only use break and continue from within such loops. In addition, continue can only jump to the beginning of a loop, and break can only jump to the end of a loop.

In practice you rarely use break and continue when writing new Kotlin code. These features are artifacts from earlier languages. Although they are occasionally useful, you’ll learn in this book that Kotlin provides superior mechanisms.

Here’s an example with a for loop containing both a continue and a break:

// BreakAndContinue/ForControl.kt
import atomictest.eq

fun main() {
  val nums = mutableListOf(0)
  for (i in 4 until 100 step 4) { // [1]
    if (i == 8) continue          // [2]
    if (i == 40) break            // [3]
    nums.add(i)
  }                               // [4]
  nums eq "[0, 4, 12, 16, 20, 24, 28, 32, 36]"
}

The example aggregates Ints into a mutable List. The continue at [2] jumps back to the beginning of the loop, which is the opening brace at [1]. It “continues” execution starting with the next iteration of the loop. Note that the code following continue inside the for loop body is not executed: nums.add(i) is not called when i == 8 so you don’t see it in the resulting nums.

When i == 40, break is executed at [3], which “breaks out” of the for loop by jumping to the end of its scope at [4]. The numbers beginning at 40 are not added to the resulting List because the for loop stops executing.

Lines [2] and [3] are interchangeable because their logic doesn’t overlap. Try swapping the lines and verify that the output doesn’t change.

We can rewrite ForControl.kt using a while loop:

// BreakAndContinue/WhileControl.kt
import atomictest.eq

fun main() {
  val nums = mutableListOf(0)
  var i = 0
  while (i < 100) {
    i += 4
    if (i == 8) continue
    if (i == 40) break
    nums.add(i)
  }
  nums eq "[0, 4, 12, 16, 20, 24, 28, 32, 36]"
}

The break and continue behavior remains the same, as it does for a do-while loop:

// BreakAndContinue/DoWhileControl.kt
import atomictest.eq

fun main() {
  val nums = mutableListOf(0)
  var i = 0
  do {
    i += 4
    if (i == 8) continue
    if (i == 40) break
    nums.add(i)
  } while (i < 100)
  nums eq "[0, 4, 12, 16, 20, 24, 28, 32, 36]"
}

A do-while loop always executes at least once, because the while test is at the end of the loop.

# Labels

Plain break and continue can jump no further than the boundaries of their local loop. Labels allow break and continue to jump to the boundaries of enclosing loops, so you aren’t limited to the scope of the current loop.

You create a label by using label@, where label can be any name. Here, the label is outer:

// BreakAndContinue/ForLabeled.kt
import atomictest.eq

fun main() {
  val strings = mutableListOf<String>()
  outer@ for (c in 'a'..'e') {
    for (i in 1..9) {
      if (i == 5) continue@outer
      if ("$c$i" == "c3") break@outer
      strings.add("$c$i")
    }
  }
  strings eq listOf("a1", "a2", "a3", "a4",
    "b1", "b2", "b3", "b4", "c1", "c2")
}

The labeled continue expression continue@outer continues back to the label outer@. The labeled break expression break@outer finds the end of the block named outer@, and proceeds from there.

Labels work with while and do-while:

// BreakAndContinue/WhileLabeled.kt
import atomictest.eq

fun main() {
  val strings = mutableListOf<String>()
  var c = 'a' - 1
  outer@ while (c < 'f') {
    c += 1
    var i = 0
    do {
      i++
      if (i == 5) continue@outer
      if ("$c$i" == "c3") break@outer
      strings.add("$c$i")
    } while (i < 10)
  }
  strings eq listOf("a1", "a2", "a3", "a4",
    "b1", "b2", "b3", "b4", "c1", "c2")
}

WhileLabeled.kt can be rewritten as:

// BreakAndContinue/Improved.kt
import atomictest.eq

fun main() {
  val strings = mutableListOf<String>()
  for (c in 'a'..'c') {
    for (i in 1..4) {
      val value = "$c$i"
      if (value < "c3") {     // [1]
        strings.add(value)
      }
    }
  }
  strings eq listOf("a1", "a2", "a3", "a4",
    "b1", "b2", "b3", "b4", "c1", "c2")
}

This is far more comprehensible. In line [1], we only add Strings that occur (alphabetically) before "c3". This produces the same behavior as using break when reaching "c3" in the previous versions of the example.

  • -

break and continue tend to create complicated and un-maintainable code. Although these jumps are somewhat more civilized than “goto,” they still interrupt program flow. Code without jumps is almost always easier to understand.

In some cases, you can write the conditions for iteration explicitly instead of using break and continue, as we did in the example above. In other cases, you can restructure your code and introduce new functions. Both break and continue can be replaced with return if you extract the whole loop or the loop body into new functions. In the next section, [Functional Programming](javascript:void(0)), you’ll learn to write clear code without using break and continue.

Consider alternative approaches, and choose the simpler and more readable solution. This typically won’t include break and continue.

Exercises and solutions can be found at www.AtomicKotlin.com.