15

I just learned today that the following Java code is perfectly legal:

myBlock: {
    /* ... code ... */

    if (doneExecutingThisBlock())
        break myBlock;

    /* ... more code ... */
}

Note that myBlock isn't a loop - it's just a block of code I've delimited with curly braces.

This seems like a rather strange feature to have. It means that you can use a named break to break out of an if statement or anonymous block, though you can't normally use a break statement in these contexts.

My question is this: is there a good reason for this design decision? That is, why make it so that you can only break out of certain enclosing statements using labeled breaks but not regular breaks? And why allow for this behavior at all? Given how (comparatively) well-designed Java is as a language I would assume there's a reason for this, but I honestly can't think of one.

GEOCHET
  • 21,119
  • 15
  • 74
  • 98
templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
  • `goto` is evil, therefore Java has labeled `break` – Trinidad Feb 24 '11 at 02:18
  • I think this is a duplicate of [Why should I give a name to an If Statement](http://stackoverflow.com/questions/4904547/why-should-i-give-a-name-to-an-if-statement) – Zach L Feb 24 '11 at 02:22
  • @Zach L- I think this question is related to your link but is fundamentally different, since the question is more about "why would the language be like this?" than "why would I as a programmer want to use this feature?" But thanks for the link! – templatetypedef Feb 24 '11 at 02:26

9 Answers9

12

It is plausible that this was done for simplicity. If originally the labeled break can only break loop statements, then it should be immediately clear to language designer that the restriction isn't necessary, the semantics work the same for all statements. For the economics of the language spec, and simpler implementation of compilers, or just out of the habit towards generality, labeled break is defined for any statement, not just loop statements.

Now we can look back and judge this choice. Does it benefit programmers, by giving them extra expression power? Seems very little, the feature is rarely used. Does it cost programmers in learning and understanding? Seems so, as evidenced by this discussion.

If you could go back time and change it, would you? I can't say I would. We have a fetish for generality.

If in a parallel universe it was limited to loop statements only, there is still a chance, probably much smaller, that someone posts the question on stackoverflow: why couldn't it work on arbitrary statements?

irreputable
  • 44,725
  • 9
  • 65
  • 93
3

Think of it as a return statement that returns from the block instead of from the entire function. The same reasoning you apply to object to break being scattered anywhere can also be applied to return being allowed anywhere except at the end of a function.

Ted Hopp
  • 232,168
  • 48
  • 399
  • 521
3

The issue with goto is that it can jump forward, past code. A labeled break cannot do that (it can only go backwards). IIRC C++ has to deal with goto jumping past code (it is been over 17 years since I cared about that though so I am not sure I am remembering that right).

Java was designed to be used by C/C++ programmers, so many things were done to make it familiar to those developers. It is possible to do a reasonable translation from C/C++ to Java (though some things are not trivial).

It is reasonable to think that they put that into the language to give C/C++ developers a safe goto (where you can only go backwards in the code) to make it more comfortable to some programmers converting over.

I have never seen that in use, and I have rarely seen a labeled break at all in 16+ years of Java programming.

You cannot break forward:

public class Test 
{
    public static void main(final String[] argv) 
    {
        int val = 1;

        X:
        {
            if(argv.length == 0)
            {
                break X;
            }

            if(argv.length == 1)
            {
                break Y;   <--- forward break will not compile
            }
        }

        val = 0;

        Y:
        {
            Sysytem.out.println(val); <-- if forward breaks were allowed this would 
                                          print out 1 not 0.
        }
    }
}
TofuBeer
  • 60,850
  • 18
  • 118
  • 163
  • 3
    Huh? Breaking to a labeled statement jumps to *after* the labelled statement - if the break is within a code block which is itself the break target it will most certainly jump "forward". – Lawrence Dol Feb 24 '11 at 03:31
  • 1
    see edit. If Java had goto (and it worked like goto in other languages) you could do goto Y, which would be a forward break. – TofuBeer Feb 24 '11 at 05:05
  • 1
    In Java you can not jump to the label, you jump to it's scope _after_ the labeled block. See http://stackoverflow.com/questions/5099628/why-does-java-allow-for-labeled-breaks-on-arbitrary-statements/5099685#5099685 – Trinidad Feb 24 '11 at 12:11
  • No real difference, the effect is the same - you name jump to the label which puts you past the } (see the code example). – TofuBeer Feb 24 '11 at 15:48
  • How do named breaks in Java interact with finally? –  Mar 04 '14 at 20:35
2

Why make it so that you can only break out of certain enclosing statements using labeled breaks but not regular breaks

Consider:

while (true) {
    if (condition) {
        break;
    }
}

If the break did as you suggest, this code would perform unexpectedly. Breaks would become a lot more difficult to use.

And why allow for this behavior at all?

I don't use it, but it is a feature and allows for certain unique control-flow constructs. I'd ask you, why not allow it?

Kirk Woll
  • 76,112
  • 22
  • 180
  • 195
2

is there a good reason for this design decision?

Yes. Because it works.

In the labelled break case, the fact that you don't need to be inside a loop or switch lets you to express things that are harder to express in other ways. (Admittedly, people rarely do use labelled break this way ... but that's not a fault of the language design.)

In the unlabelled break case, the behavior is to break out of the innermost enclosing loop or switch. If it was to break out of the innermost enclosing statement, then a lot of things would be much harder to express, and many would probably require a labelled block. For example:

while (...) {
     /* ... */
     if (something) break;
     /* ... */
}

If break broke out of the innermost enclosing statement, then it wouldn't break out of the loop.


There is another possible reason / rationale. Remember that Java was a brand new language and a relatively early adopter of exceptions and exception handling.

Consider this:

try {
    /* ... code ... */

    if (doneExecutingThisBlock())
        throw new OuttaHere();

    /* ... more code ... */
} catch (OuttaHere e) {
    /* do nothing */
}

According to the dogma, that is bad code. You shouldn't use exceptions for "normal" flow control.

(Pragmatically, that it also very inefficient due to the overheads of exception creation and handling. Exceptions performance was improved significantly in Java 8, I think, but that was ~20 years later.)

Now imagine that you are a language designer, and you feel that you have to provide an alternative to the "exceptions as flow control" anti-pattern. The "break to label" construct does exactly that. Compare the above with the example in the question.

In hindsight, this is unnecessary. The above can be done in other ways; i.e. without labelled break. In practice this construct is used so rarely that many (maybe most) programmers don't even know it exists in Java.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • I fully go with the 'because it works' line. Although it may seem ironic, I really miss this kind of approach in Java circles. –  Apr 09 '13 at 13:19
1

The ability to leave a sequence of statements has been implemented in several programming languages before Java. Two examples:

Algol-68 had exit to terminate the execution of the smallest closed-clause (very loosely speaking, a begin ... end sequence).

BLISS had labelled BEGIN … END blocks, with a LEAVE statement to terminate execution.

Implementations with labels (as in Java) are more flexible in that they can exit nested blocks (or compound statements, or whatever you call them in your language of choice); without the label, you're limited to exiting a single "level" only.

Answering the direct question, "why" -- because it's been found to be a useful construct in other, prior, languages.

0

It's the "structured" equivalent to a goto, useful in certain circumstances.

I quite often use such a label create named sub-blocks in a method to tightly limit scope of variables or to simply label a block of code which is not appropriate to break out into a separate function. That is, I use it to label a block so that the code structure around braces is preserved. Here's an example in C for a JNI call, and I do the same in Java:

JNIEXPORT void JNICALL Java_xxx_SystemCall_jniChangePassword(JNIEnv *jep, jobject thsObj,
 jlong handle, jbyteArray rndkey, jbyteArray usrprf, jbyteArray curpwd, jbyteArray newpwd, jint pwdccs, jint tmosec) {
    Message                             rqs,rpy;

    thsObj=thsObj;

    SetupRequest: {
        memset(&rqs,0,sizeof(rqs));
        setOpcode(&rqs,"CHGPWD");
        if(!setField(mFldAndLen(rqs.rnd               ),null                      ,jep,rndkey,"Random Key")) {
            return;
            }
        if(!setField(mFldAndLen(rqs.dta.chgpwd.user   ),&rqs.dta.chgpwd.userLen   ,jep,usrprf,"User Profile")) {
            return;
            }
        if(!setField(mFldAndLen(rqs.dta.chgpwd.curPass),&rqs.dta.chgpwd.curPassLen,jep,curpwd,"Cur Password")) {
            return;
            }
        if(!setField(mFldAndLen(rqs.dta.chgpwd.newPass),&rqs.dta.chgpwd.newPassLen,jep,newpwd,"New Password")) {
            return;
            }
        rqs.dta.chgpwd.ccsid=pwdccs;
        }
    ...
Lawrence Dol
  • 63,018
  • 25
  • 139
  • 189
  • 1
    no need to name the blocks.. just do { /* code goes here */ } anywhere in a method (and no I did not do the -1). – TofuBeer Feb 24 '11 at 02:57
  • @Tofu: That leaves structurally orphaned braces in the code, which I detest. – Lawrence Dol Feb 24 '11 at 03:25
  • @Tofu: IYNSHO?? I disagree; the result would be unnecessarily fragmented, and worse for it. But this isn't the greatest example - I would normally use it to limit scope of variables declared within the block. – Lawrence Dol Feb 24 '11 at 07:13
  • 2
    You already fragmented it by giving it a name? Why not just go the extra distance and give it a proper name? Personally I have, on average, about 10 lines of code per method. It is very rare to get to 20. Also, I used a :-P for a reason :-) – TofuBeer Feb 24 '11 at 07:45
0

The break statement terminates the labeled statement; it does not transfer the flow of control to the label. Control flow is transferred to the statement immediately following the labeled (terminated) statement.

It seems to be useful to exit nested loops. See http://download.oracle.com/javase/tutorial/java/nutsandbolts/branch.html

It's semantically the same as is there a equivalent of Java's labelled break in C# or a workaround

Community
  • 1
  • 1
Trinidad
  • 2,756
  • 2
  • 25
  • 43
0

Adding to Stephen C's answer, if (something) you cannot break out of a nested loop. These situations do happen in numerical algorithms. One simple example here - you cannot break out of the i-loop without the named for. Hope this helps.

public class JBreak  {

    private int brj;

    public JBreak (String arg) {
        brj = Integer.parseInt (arg);       
    }

    public void print () {
        jbreak:
        for (int i = 1 ; i < 3 ; i++) {
            for (int j = 0 ; j < 5 ; j++) {
                if ((i*j) == brj)
                    break jbreak;
                System.out.println ("i,j: " + i + "," + j);
    }}}

    public static void main (String[] args) {
        new JBreak(args[0]).print();
}}
Manidip Sengupta
  • 3,573
  • 5
  • 25
  • 27