Skip to content

Java Tip: Labelled Breaks & Continues

One of the design decisions made during the development of Java was the exclusion of the goto statement. The pros and cons of goto have been debated for countless ages, so I won’t go into that here. Without the goto, one would think that there would be no use for labels in Java. But that’s not the case. Java has a neat little feature that makes use of labels which C and C++ do not have.

Consider the following code:


Object obj = null;
for(int i=0; i < array1.length; ++i) {
    for(int j=0; i < array2.length; ++i) {
        if(array1[i] == array2[i]) {
            obj = array1[i];
            break;
        }
    }
    if(obj != null) {
       break;
    }
}
// do some work on object

This sample should be easy enough to follow. Each object in array1 is compared to each object in array2 to see if they are the same instance. If a match is found in the inner loop, it breaks and control returns to the outer loop. The if block at the end of the outer loop is necessary - if a match was found in the inner loop you don’t want to process anymore.

This is something you will see now and again in different situations - two loops with a value comparison in the inner, both required to break when a match is found. There’s nothing wrong with the code as is. It serves its purpose. But that last if statement is just an eyesore, isn’t it? If there were no inner loop, one break statement would be all you need. What if you need a third nested loop inside the second one? Now you need to add an if check to the second loop along with another break statement. Not pretty.

Luckily, Java has a neat feature called Labelled Breaks. It’s very simple and functions like a restricted goto statement. Assign a label to the outer loop, then break to that label when you need to. The example can then be rewritten thusly:


Object obj = null;
Outer:
for(int i=0; i < array1.length; ++i) {
    for(int j=0; i < array2.length; ++i) {
        if(array1[i] == array2[i]) {
            obj = array1[i];
            break Outer;
        }
    }
}

The important thing to remember is that control passes to whichever loop follows the label. What happens then depends on what whether it is a labelled break or a labelled continue that was executed. In the above example, it was a labelled break, so the labelled loop will exit.

I did say the functionality is similar to a restricted goto. And the restriction is in where you place the label. It can’t go just any old place. It must precede the outermost statement you wish to break out of. It doesn’t matter how much space is bettween the labels and the loop as long as no other statements or expressions come between them:


// OK
SomeLabel: while(x==y) {
}

// OK
AnotherLabel:
while(x==y) {
}

// OK
YetAnotherLabel:

while(x==y) {
}

// ERROR
BadLabel:
x = 0;
while(x==0) {
   break BadLabel; // the error will be generated on this line
}

Not much to it. I like to keep my labels on the same line as the loop statement for clarity. In a good text editor, when you usually have a few tabs between the left margin and a line of code, it’s clearest if you push the label all the way against the left margin so that you wind up with something like this:


                       int x = 0;
                       int y = 0;
SomeLabel:        while(x==y) {
                       }

For completeness, here’s an example of using a labelled continue:


SomeLabel:
while(x == y) {
     while(i == j) {
         if(i == x) {
             continue SomeLabel;
         }
     }
     // if the above labelled continue executes, the code below will not execute and
     // control will pass back to the top of the outer loop for the next iteration. The
     // effect is the same as if you put a break statement in the inner loop, and a
     // continue statement right here.
     i += y;
}

So to summarize, the labels can precede any loop construct: for, while, or do…while. When a labelled break is executed, control propagates up to the loop that has a matching label. If a labelled break was executed, the labelled loop will break. If a labelled continue was executed, the labelled loop will continue immediately with the next iteration. No statements or expressions can appear between the label and the loop it wraps. And I didn’t mention it (though the examples all show it), you can only break or continue to a labelled loop in the same nested loop heirarchy.

This tip is something many new, and even some intermediate, Java programmers aren’t aware of. I had planned to share a useful utility class today. But since it makes use of a labelled break, I thought it would be better to explain those first. The utility class will come tomorrow.

Post a Comment

Your email is never published nor shared. Required fields are marked *