Java中的goto语句的替代方法
Java中goto关键字的替代函数是什么?
由于Java没有转到。
您可以使用带有标签的BREAK语句:
search: for (i = 0; i < arrayOfInts.length; i++) { for (j = 0; j < arrayOfInts[i].length; j++) { if (arrayOfInts[i][j] == searchfor) { foundIt = true; break search; } } }
但是,在devise正确的代码中,您不应该需要GOTOfunction。
Java中没有与goto
概念直接等价的东西。 有几个结构可以让你做一些你可以用一个经典的goto
做的事情。
-
break
和continue
语句允许您跳出循环或switch语句中的块。 - 带标签的语句和
break <label>
允许您跳出任意复合语句到给定方法(或初始化块)中的任何级别。 - 如果您为循环语句添加标签,则可以
continue <label>
继续从内部循环进行外部循环的下一次迭代。 - 抛出和捕获exception允许您(有效地)跳出方法调用的多个级别。 (但是,例外情况相对昂贵,并且被认为是做“普通”控制stream程1的坏方法。)
- 当然,还有
return
。
这些Java结构中的任何一个都不允许您在与当前语句相同的嵌套级别上向后或向代码中的某个点分支。 他们都跳出一个或多个嵌套(示波器)级别,他们都(除了continue
)跳下去。 这个限制有助于避免旧的BASIC,FORTRAN和COBOL代码2中固有的goto“意大利面代码”症状。
1-exception中最昂贵的部分是实际创buildexception对象及其堆栈跟踪。 如果真的需要为“正常”stream控制使用exception处理,则可以预先分配/重用exception对象,也可以创build自定义exception类来覆盖fillInStackTrace()
方法。 缺点是,exception的printStackTrace()
方法不会给你有用的信息…你应该永远需要给他们打电话。
2 – 意大利面条代码综合症引发了结构化编程方法,在这种方法中限制了可用语言结构的使用。 这可以应用到BASIC , Fortran和COBOL ,但需要谨慎和纪律。 摆脱goto
完全是一个务实的更好的解决scheme。 如果你保持一种语言,总会有一些小丑会滥用它。
为了好玩, 这里是Java中的GOTO实现。
例:
1 public class GotoDemo { 2 public static void main(String[] args) { 3 int i = 3; 4 System.out.println(i); 5 i = i - 1; 6 if (i >= 0) { 7 GotoFactory.getSharedInstance().getGoto().go(4); 8 } 9 10 try { 11 System.out.print("Hell"); 12 if (Math.random() > 0) throw new Exception(); 13 System.out.println("World!"); 14 } catch (Exception e) { 15 System.out.print("o "); 16 GotoFactory.getSharedInstance().getGoto().go(13); 17 } 18 } 19 }
运行它:
$ java -cp bin:asm-3.1.jar GotoClassLoader GotoDemo 3 2 1 0 Hello World!
我需要添加“不要使用它!”吗?
虽然有些评论者和downvoters认为这不是转到 ,从下面的Java语句生成的字节码确实表明这些语句确实expressiongoto语义。
具体来说, do {...} while(true);
循环在第二个例子中被Java编译器优化,以便不评估循环条件。
向前跳
label: { // do stuff if (check) break label; // do more stuff }
在字节码中:
2 iload_1 [check] 3 ifeq 6 // Jumping forward 6 ..
向后跳
label: do { // do stuff if (check) continue label; // do more stuff break label; } while(true);
在字节码中:
2 iload_1 [check] 3 ifeq 9 6 goto 2 // Jumping backward 9 ..
如果你真的想要goto语句,你总是可以尝试打破命名块。
你必须在块的范围内打破标签:
namedBlock: { if (j==2) { // this will take you to the label above break namedBlock; } }
我不会告诉你为什么你应该避免goto的 – 我假设你已经知道这个答案。
public class TestLabel { enum Label{LABEL1, LABEL2, LABEL3, LABEL4} /** * @param args */ public static void main(String[] args) { Label label = Label.LABEL1; while(true) { switch(label){ case LABEL1: print(label); case LABEL2: print(label); label = Label.LABEL4; continue; case LABEL3: print(label); label = Label.LABEL1; break; case LABEL4: print(label); label = Label.LABEL3; continue; } break; } } public final static void print(Label label){ System.out.println(label); }
斯蒂芬C写道:
有两个构造允许你做一些你可以做的一些经典的goto。
多一个…
马特沃尔夫写道:
人们总是谈论从不使用goto,但我认为有一个非常好的现实世界的用例,这是非常知名和使用的。也就是说,确保在从函数返回之前执行一些代码。通常它的释放锁或什么不是,但在我的情况下,我很乐意能够在返回之前跳到一个rest,所以我可以做必要的强制性清理。
try { // do stuff return result; // or break, etc. } finally { // clean up before actually returning, even though the order looks wrong. }
http://docs.oracle.com/javase/tutorial/essential/exceptions/finally.html
finally块总是在try块退出时执行。 这确保即使发生意外的exception也能执行finally块。 但是最后对于不仅仅是exception处理而言是有用的 – 它允许程序员避免由于返回,继续或中断而意外绕过清除代码。 清理代码放在finally块里总是一个很好的习惯,即使没有预期的例外。
最后一个与之相关的愚蠢的面试问题是:如果你从一个try {}块返回,但是你的finally {}也有一个return,那么返回哪个值?
尝试下面的代码。 这个对我有用。
for (int iTaksa = 1; iTaksa <=8; iTaksa++) { // 'Count 8 Loop is 8 Taksa strTaksaStringStar[iCountTaksa] = strTaksaStringCount[iTaksa]; LabelEndTaksa_Exit : { if (iCountTaksa == 1) { //If count is 6 then next it's 2 iCountTaksa = 2; break LabelEndTaksa_Exit; } if (iCountTaksa == 2) { //If count is 2 then next it's 3 iCountTaksa = 3; break LabelEndTaksa_Exit; } if (iCountTaksa == 3) { //If count is 3 then next it's 4 iCountTaksa = 4; break LabelEndTaksa_Exit; } if (iCountTaksa == 4) { //If count is 4 then next it's 7 iCountTaksa = 7; break LabelEndTaksa_Exit; } if (iCountTaksa == 7) { //If count is 7 then next it's 5 iCountTaksa = 5; break LabelEndTaksa_Exit; } if (iCountTaksa == 5) { //If count is 5 then next it's 8 iCountTaksa = 8; break LabelEndTaksa_Exit; } if (iCountTaksa == 8) { //If count is 8 then next it's 6 iCountTaksa = 6; break LabelEndTaksa_Exit; } if (iCountTaksa == 6) { //If count is 6 then loop 1 as 1 2 3 4 7 5 8 6 --> 1 iCountTaksa = 1; break LabelEndTaksa_Exit; } } //LabelEndTaksa_Exit : { } // "for (int iTaksa = 1; iTaksa <=8; iTaksa++) {"
最简单的是:
int label = 0; loop:while(true) { switch(state) { case 0: // Some code state = 5; break; case 2: // Some code state = 4; break; ... default: break loop; } }
使用标签中断作为转到的替代方法。
Java没有goto
,因为它使代码非结构化和不清楚读取。 然而,你可以使用break
, continue
作为文明的forms,没有问题。
向前跳转使用rest –
ahead: { System.out.println("Before break"); break ahead; System.out.println("After Break"); // This won't execute } // After a line break ahead, the code flow starts from here, after the ahead block System.out.println("After ahead");
输出 :
Before Break After ahead
继续向后跳
before: { System.out.println("Continue"); continue before; }
这将导致一个无限循环,因为每一行在continue before
都会continue before
执行, 代码stream将从before
再次before
。