A plain break or continue isn't always enough. Searching through a grid of warehouses or scanning a list of carts often requires bailing out of more than just the innermost loop. Java's labeled statements provide that capability: attach a name to a loop, then break or continue to that name instead of the nearest one. This lesson covers when to use them, how the syntax works, and when an extracted method is the better choice.
A label is an identifier followed by a colon, placed right before a loop. The label doesn't do anything on its own. It only matters when a break or continue names it.
The label warehouseSearch: sits on the outer for. When break warehouseSearch; fires, control jumps out of both loops in one step. Without the label, a plain break would only exit the inner loop and the outer one would keep going.
Naming rules for labels follow the same rules as variable names: letters, digits, underscores, no leading digit, no keywords. Pick names that describe what the loop is doing. outer: works but reads poorly. warehouseSearch: or cartScan: tells the reader what's going on.
Java has no goto keyword. Labels are not a back door to one. They only work with break and continue, and only to jump out of or skip an enclosing loop. Arbitrary forward or backward jumps to a label are not allowed.
break Falls ShortTo see why labels exist, look at what a plain break does in a nested loop. A plain break always exits the nearest enclosing loop. That's fine in a single loop. In nested loops, it's often the wrong behavior.
What's wrong with this code?
The break does its job: it leaves the inner loop the instant the product matches. But the outer loop continues, moves on to the next aisle, and keeps printing. Scanning aisle 2 after the answer was already found is wasted work.
The usual fix without labels is a flag plus an extra check:
That works, but it carries state (found) just to coordinate two loops. A labeled break removes the flag.
Fix with a labeled break:
One break warehouseSearch; exits both loops together. No flag, no extra condition in the outer header, no wasted iterations.
break FlowsCompare the control flow side by side. A plain break exits one level. A labeled break exits straight to the statement after the labeled loop, regardless of nesting depth.
The two red and green endpoints make the difference clear. A plain break returns to the outer loop's header to check the next iteration. A labeled break goes all the way out, skipping the rest of the outer loop entirely.
This also extends to three or more levels. With three nested loops and the outermost labeled, break theOutermost; from the deepest body exits all three at once.
continuecontinue has the same problem in nested loops, just less common. A plain continue jumps to the next iteration of the nearest loop, which is the inner one. A labeled continue jumps to the next iteration of the labeled loop.
This is useful for skipping the rest of an outer iteration based on something discovered in the inner loop. Consider checking a list of shopping carts and skipping any cart that contains an out-of-stock item.
When continue outerCart; fires for cart 1, control jumps straight to the top of the outer loop and moves on to cart 2. The "ready to ship" line below the inner loop never runs for cart 1, because labeled continue skips the rest of that outer iteration.
A plain continue there would skip to the next item in the same cart, the opposite of the desired behavior.
Putting it together, a complete search over a 2D inventory that reports the position of the first match and stops cleanly:
The labeled break saves the position variables before exiting. That's a typical pattern: exiting a search usually requires remembering where the match was found. The variables live in the enclosing scope so they're still readable after the loops finish.
Labeled break and continue have no runtime overhead. They compile to the same kind of jump as plain break and continue. The cost is purely in readability, not performance.
Labels are uncommon in everyday Java code. They have legitimate uses (the search example above is one), but most code that uses a label has a clearer alternative: pull the loops into their own method and use return.
return exits any number of nested loops at once. It also gives the search a name (findProduct) and makes the result obvious from the type signature. This version usually reads better in code review.
When does a label fit? When the loops do real work that touches surrounding state, splitting them into a method would force passing and returning a long list of values, and the logic is clearly tied to where it lives. That's a narrow case, but it does come up.
A reasonable guideline:
A label has to sit immediately before a statement, and the statement it labels is the only one it applies to. In practice, that statement is almost always a loop (for, while, or do-while). A { } block or a switch can technically be labeled, but those uses are rare and usually a sign that something else needs refactoring.
The label is only visible inside the statement it labels. Break or continue to a label from outside its scope is not allowed. Reusing the same label name for two different loops in the same nesting is also rejected by the compiler.
continue cartScan; ends the current outer iteration as soon as i reaches 2, so item 2 is never printed for any cart.
9 quizzes