skip to content

Explain the difference between `continue@outer` and `break@outer` in a nested loop, and trace the output of a short example for each.

level: middleimportance: must knowfreq 55%

answer

  1. break@outer = leave the labeled loop
  2. continue@outer = advance the labeled loop
  3. continue@outer skips code after the inner loop too
  4. plain break runs outer's post-inner code; continue@outer does not
  5. trace by writing i,j on each step

basics

~20 s

break@outer quits the named outer loop completely. continue@outer skips the rest of the current inner work and jumps to the outer loop's next iteration. Both target the labeled loop, but one stops it, the other advances it.

solid answer

~50 s

Both jumps target the loop carrying the `outer@` label, but they do opposite things. `break@outer` terminates the labeled loop entirely — control resumes after the outer loop. `continue@outer` ends the current iteration of the labeled loop and proceeds to its next iteration, skipping any remaining inner-loop iterations. The key trace difference: with `break@outer`, once the condition hits you see no further output at all; with `continue@outer`, the inner loop is cut short but the outer index keeps advancing so you keep getting one line per outer value. Plain `break`/`continue` would instead act on the inner loop. A common interview trap is mixing these up: `continue@outer` is NOT the same as plain `break` of the inner loop, because plain inner `break` lets the outer loop run its remaining statements after the inner loop, whereas `continue@outer` skips straight to the outer loop's next iteration.

code

kotlin · 7 lines
kotlin
outer@ for (i in 1..3) {
    for (j in 1..3) {
        if (j == 2) continue@outer
        println("$i,$j")
    }
    println("end of i=$i")  // never printed: continue@outer skips it
}

go deeper

for a junior

Knows break@outer stops the outer loop and continue@outer advances it.

for a middle

Correctly traces both outputs and explains the labeled-loop target.

for a senior

Identifies the trailing-code edge case distinguishing plain break from continue@outer.

for a principal

Discusses when such control flow signals the loop should be refactored into a named function for clarity.

## Setup Assume: ```kotlin outer@ for (i in 1..3) { for (j in 1..3) { if (j == 2) /* JUMP */ println("$i,$j") } } ``` We'll substitute `break@outer` and `continue@outer` for `/* JUMP */`. ## `break@outer` `break@outer` **terminates the outer (labeled) loop entirely**. Execution leaves the whole nested structure. Trace: `i=1, j=1` -> prints `1,1`. `j=2` -> `break@outer` fires -> done. ``` 1,1 ``` That is the entire output. The outer loop never reaches `i=2`. ## `continue@outer` `continue@outer` **ends the current iteration of the outer loop and advances it**. The remaining inner iterations are skipped, and `i` moves on. Trace: - `i=1, j=1` -> prints `1,1`; `j=2` -> `continue@outer` -> skip `j=3`, advance `i`. - `i=2, j=1` -> prints `2,1`; `j=2` -> `continue@outer` -> advance `i`. - `i=3, j=1` -> prints `3,1`; `j=2` -> `continue@outer` -> outer loop ends. ``` 1,1 2,1 3,1 ``` ## Contrast with plain inner jumps | Jump | Effect | |------|--------| | `break` | stop inner loop; outer continues, running any code after the inner loop | | `continue` | next iteration of inner loop | | `break@outer` | stop outer loop entirely | | `continue@outer` | next iteration of outer loop, skipping rest of inner loop | The subtle point: plain inner `break` and `continue@outer` differ when there is code **after** the inner loop but **inside** the outer loop. Plain `break` still runs that code; `continue@outer` skips it and goes straight to the next outer iteration. ```kotlin outer@ for (i in 1..2) { for (j in 1..2) { if (j == 1) continue@outer println("inner $i,$j") } println("after inner $i") // SKIPPED by continue@outer, run by plain break } // continue@outer prints nothing from inner and skips 'after inner' ```

  • When does plain inner `break` differ observably from `continue@outer`?
    Only when there is code in the outer loop after the inner loop. Plain break runs that trailing code; continue@outer skips it and advances the outer loop.
  • Does `continue@outer` re-run the outer loop's initialization for the next index?
    It advances the iterator like a normal iteration boundary; for a range-based for, the next value is produced by the range's iterator.

saying these in an interview costs you the question

  • Saying continue@outer restarts the inner loop from j=1 in the same i
  • Claiming break@outer and continue@outer produce the same output
  • Ignoring trailing outer-loop code when comparing to plain break
  • Believing continue@outer is illegal without a do-while

context