85

Java中goto关键字的替代函数是什么?

由于 Java 没有 goto。

4

11 回答 11

84

您可以使用带标签的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;
            }
        }
    }

但是,在正确设计的代码中,您不应该需要 GOTO 功能。

于 2010-03-12T05:54:46.900 回答
42

没有任何直接等同goto于 Java 中的概念。有一些结构可以让你做一些你可以用经典做的事情goto

  • breakandcontinue语句允许您跳出循环或 switch 语句中的块。
  • 带标签的语句,break <label>允许您从任意复合语句跳到给定方法(或初始化程序块)内的任何级别。
  • 如果您标记循环语句,则可以continue <label>从内部循环继续进行外部循环的下一次迭代。
  • 抛出和捕获异常允许您(有效地)跳出方法调用的多个级别。(但是,异常相对昂贵,并且被认为是执行“普通”控制流1的不好方法。)
  • 当然,还有return.

这些 Java 构造都不允许您向后分支或指向代码中与当前语句处于同一嵌套级别的点。它们都跳出一个或多个嵌套(范围)级别,并且都(除了continue)向下跳。此限制有助于避免旧 BASIC、FORTRAN 和 COBOL 代码2中固有的 goto “意大利面条代码”综合症。


1-异常中最昂贵的部分是异常对象及其堆栈跟踪的实际创建。如果您真的非常需要对“正常”流控制使用异常处理,您可以预先分配/重用异常对象,或者创建一个覆盖该fillInStackTrace()方法的自定义异常类。缺点是异常的printStackTrace()方法不会为您提供有用的信息……如果您需要调用它们。

2 - 意大利面条代码综合症催生了结构化编程方法,在这种方法中,您限制了对可用语言结构的使用。这可以应用于BASICFortranCOBOL,但它需要谨慎和自律。完全摆脱goto是一个务实的更好的解决方案。如果你把它保留在一种语言中,总会有一些小丑会滥用它。

于 2010-03-12T06:03:07.057 回答
31

只是为了好玩,这里是 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!

我需要添加“不要使用它!”吗?

于 2010-03-12T06:50:17.723 回答
18

虽然一些评论者和反对者认为这不是goto,但从以下 Java 语句生成的字节码确实表明这些语句确实表达了goto语义。

具体来说,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  ..
于 2011-06-16T14:08:51.083 回答
5

如果你真的想要 goto 语句之类的东西,你总是可以尝试打破命名块。

您必须在块的范围内才能打破标签:

namedBlock: {
  if (j==2) {
    // this will take you to the label above
    break namedBlock;
  }
}

我不会告诉你为什么你应该避免使用 goto - 我假设你已经知道答案了。

于 2010-03-12T05:58:10.450 回答
4
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);
    }
于 2011-03-04T08:30:26.597 回答
3

斯蒂芬C写道:

有两种结构可以让你做一些你可以用经典 goto 做的事情。

多一个...

马特沃尔夫写道:

人们总是谈论从不使用 goto,但我认为有一个非常好的现实世界用例,它是众所周知和使用的。也就是说,确保在函数返回之前执行一些代码。通常它的释放锁或其他什么,但就我而言,我希望能够在返回之前跳到休息,这样我就可以进行必要的强制清理。

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 块退出时执行。这样可以确保即使发生意外异常也会执行 finally 块。但 finally 不仅仅对异常处理有用——它允许程序员避免清理代码意外地被 return、continue 或 break 绕过。将清理代码放在 finally 块中始终是一个好习惯,即使没有预料到异常也是如此。

与 finally 相关的愚蠢面试问题是:如果您从 try{} 块返回,但在 finally{} 中也有 return,那么返回哪个值?

于 2013-02-07T14:36:33.537 回答
1

最简单的是:

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;
    }
}
于 2014-03-17T10:58:56.620 回答
0

试试下面的代码。这个对我有用。

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++) {"
于 2013-03-16T14:53:46.010 回答
-1

Use a labeled break as an alternative to goto.

于 2014-11-25T09:12:50.887 回答
-1

Java 没有goto,因为它使代码变得非结构化难以阅读。但是,您可以使用breakcontinue作为goto的文明形式,而不会出现问题。


使用 break 向前跳跃 -

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

使用 continue 向后跳转

before: {
    System.out.println("Continue");
    continue before;
}

这将导致无限循环,因为每次continue before执行该行时,代码流都会从before.

于 2014-12-08T07:23:36.027 回答