I just learned today that the following Java code is perfectly legal:
我今天才知道,下面的Java代码是完全合法的:
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.
注意,myBlock不是一个循环——它只是我用花括号分隔的代码块。
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.
这似乎是一个相当奇怪的特征。这意味着您可以使用一个已命名的break来突破if语句或匿名块,尽管您通常不能在这些上下文中使用break语句。
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 break
s but not regular break
s? 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.
我的问题是:这个设计决定是否有充分的理由?也就是说,为什么你只能用带标记的破折号而不是常规的破折号来破折号?为什么要允许这种行为呢?考虑到(相对而言)设计良好的Java是一种语言,我认为这是有原因的,但老实说,我想不出来。
8 个解决方案
#1
9
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.
这似乎是为了简单起见。如果最初标记的break只能中断循环语句,那么语言设计器应该立即清楚地认识到这个限制是不必要的,所有语句的语义都是一样的。对于语言规范的经济性和编译器更简单的实现,或者出于通用性的习惯,对任何语句都定义了带标记的break,而不仅仅是循环语句。
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 *: why couldn't it work on arbitrary statements?
如果在一个平行的宇宙中,它仅仅局限于循环语句,那么仍然有机会(可能要小得多)有人在*上发布了一个问题:为什么它不能处理任意语句?
#2
2
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.
可以将它看作一个返回语句,它从块中返回,而不是从整个函数中返回。同样的道理,你可以应用到物体上,以打破分散在任何地方,也可以应用到任何地方的返回,除了在一个函数的末端。
#3
2
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).
goto的问题是它可以向前跳转,跳过代码。标记的断点不能做到这一点(它只能返回)。IIRC c++必须处理goto跳过代码的问题(我已经有17年没有考虑过这个问题了,所以我不确定我是否记得对了)。
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).
Java是为C/ c++程序员设计的,为了让这些开发人员熟悉Java,他们做了很多工作。从C/ c++到Java进行合理的转换是可能的(尽管有些事情并不简单)。
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.
我们可以合理地认为,他们将其放入语言中是为了给C/ c++开发人员提供一个安全的访问(在这里,您只能返回到代码中),以使某些程序员能够更轻松地进行转换。
I have never seen that in use, and I have rarely seen a labeled break at all in 16+ years of Java programming.
我从未在使用中见过这种方法,在16年多的Java编程中,我也几乎没有见过有标记的中断。
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.
}
}
}
#4
1
Why make it so that you can only break out of certain enclosing statements using labeled breaks but not regular breaks
为什么要这样做,以便只能使用带标记的break而不是常规break来突破某些封闭语句
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?
我不使用它,但它是一个特性,允许某些独特的控制流结构。我想问你,为什么不允许呢?
#5
1
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.)
在带标签的break情况下,您不需要进入循环或交换机,这一事实使您能够以其他方式表达更难于表达的内容。(无可否认,人们很少这样使用带标签的break……)但这并不是语言设计的错。
In the unlabelled break case, the behaviour 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.
如果跳出最内层的封闭语句,那么它就不会跳出循环。
#6
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.
添加到Stephen C的答案中,如果(某事)不能跳出嵌套循环。这些情况确实发生在数值算法中。这里有一个简单的例子——如果没有命名,就不能跳出i-loop。希望这个有帮助。
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();
}}
#7
0
It's the "structured" equivalent to a goto, useful in certain circumstances.
它是“结构化的”,相当于goto,在某些情况下很有用。
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:
我经常在方法中使用这样的标签来创建命名子块,以严格限制变量的范围,或者仅仅标记一段不适合分割成单独函数的代码块。也就是说,我使用它来标记一个块,以便保留围绕大括号的代码结构。这里有一个在C中调用JNI的例子,我在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;
}
...
#8
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.
break语句终止有标记的语句;它不会将控制流转移到标签。控制流在标记(终止)语句之后立即转移到语句。
It seems to be useful to exit nested loops. See http://download.oracle.com/javase/tutorial/java/nutsandbolts/branch.html
退出嵌套循环似乎很有用。参见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
它在语义上与c#中的Java标记中断或工作区是相同的
#1
9
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.
这似乎是为了简单起见。如果最初标记的break只能中断循环语句,那么语言设计器应该立即清楚地认识到这个限制是不必要的,所有语句的语义都是一样的。对于语言规范的经济性和编译器更简单的实现,或者出于通用性的习惯,对任何语句都定义了带标记的break,而不仅仅是循环语句。
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 *: why couldn't it work on arbitrary statements?
如果在一个平行的宇宙中,它仅仅局限于循环语句,那么仍然有机会(可能要小得多)有人在*上发布了一个问题:为什么它不能处理任意语句?
#2
2
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.
可以将它看作一个返回语句,它从块中返回,而不是从整个函数中返回。同样的道理,你可以应用到物体上,以打破分散在任何地方,也可以应用到任何地方的返回,除了在一个函数的末端。
#3
2
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).
goto的问题是它可以向前跳转,跳过代码。标记的断点不能做到这一点(它只能返回)。IIRC c++必须处理goto跳过代码的问题(我已经有17年没有考虑过这个问题了,所以我不确定我是否记得对了)。
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).
Java是为C/ c++程序员设计的,为了让这些开发人员熟悉Java,他们做了很多工作。从C/ c++到Java进行合理的转换是可能的(尽管有些事情并不简单)。
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.
我们可以合理地认为,他们将其放入语言中是为了给C/ c++开发人员提供一个安全的访问(在这里,您只能返回到代码中),以使某些程序员能够更轻松地进行转换。
I have never seen that in use, and I have rarely seen a labeled break at all in 16+ years of Java programming.
我从未在使用中见过这种方法,在16年多的Java编程中,我也几乎没有见过有标记的中断。
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.
}
}
}
#4
1
Why make it so that you can only break out of certain enclosing statements using labeled breaks but not regular breaks
为什么要这样做,以便只能使用带标记的break而不是常规break来突破某些封闭语句
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?
我不使用它,但它是一个特性,允许某些独特的控制流结构。我想问你,为什么不允许呢?
#5
1
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.)
在带标签的break情况下,您不需要进入循环或交换机,这一事实使您能够以其他方式表达更难于表达的内容。(无可否认,人们很少这样使用带标签的break……)但这并不是语言设计的错。
In the unlabelled break case, the behaviour 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.
如果跳出最内层的封闭语句,那么它就不会跳出循环。
#6
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.
添加到Stephen C的答案中,如果(某事)不能跳出嵌套循环。这些情况确实发生在数值算法中。这里有一个简单的例子——如果没有命名,就不能跳出i-loop。希望这个有帮助。
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();
}}
#7
0
It's the "structured" equivalent to a goto, useful in certain circumstances.
它是“结构化的”,相当于goto,在某些情况下很有用。
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:
我经常在方法中使用这样的标签来创建命名子块,以严格限制变量的范围,或者仅仅标记一段不适合分割成单独函数的代码块。也就是说,我使用它来标记一个块,以便保留围绕大括号的代码结构。这里有一个在C中调用JNI的例子,我在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;
}
...
#8
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.
break语句终止有标记的语句;它不会将控制流转移到标签。控制流在标记(终止)语句之后立即转移到语句。
It seems to be useful to exit nested loops. See http://download.oracle.com/javase/tutorial/java/nutsandbolts/branch.html
退出嵌套循环似乎很有用。参见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
它在语义上与c#中的Java标记中断或工作区是相同的