替代 Java 中的 goto 语句

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2430782/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 07:32:18  来源:igfitidea点击:

Alternative to a goto statement in Java

javakeywordgoto

提问by gmhk

What is an alternative function for the gotokeyword in Java?

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

Since Java does not have a goto.

因为Java没有goto。

采纳答案by Padmarag

You could use a labeled BREAKstatement:

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

However, in properly designed code, you shouldn't need GOTO functionality.

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

回答by Amir Afghani

If you really want something like goto statements, you could always try breaking to named blocks.

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

You have to be within the scope of the block to break to the label:

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

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

I won't lecture you on why you should avoid goto's - I'm assuming you already know the answer to that.

我不会教你为什么要避免使用 goto - 我假设你已经知道答案了。

回答by Stephen C

There isn't any direct equivalent to the gotoconcept in Java. There are a few constructs that allow you to do someof the things you can do with a classic goto.

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

  • The breakand continuestatements allow you to jump out of a block in a loop or switch statement.
  • A labeled statement and break <label>allow you to jump out of an arbitrary compound statement to any level within a given method (or initializer block).
  • If you label a loop statement, you can continue <label>to continue with the next iteration of an outer loop from an inner loop.
  • Throwing and catching exceptions allows you to (effectively) jump out of many levels of a method call. (However, exceptions are relatively expensive and are considered to be a bad way to do "ordinary" control flow1.)
  • And of course, there is return.
  • breakcontinue语句,可以在循环或switch语句跳跃块了。
  • 带标签的语句,break <label>允许您从任意复合语句跳到给定方法(或初始化程序块)中的任何级别。
  • 如果标记循环语句,则可以continue <label>从内循环继续外循环的下一次迭代。
  • 抛出和捕获异常允许您(有效地)跳出方法调用的多个级别。(但是,异常相对昂贵,并且被认为是执行“普通”控制流1的不好方法。)
  • 当然,还有return

None of these Java constructs allow you to branch backwards or to a point in the code at the same level of nesting as the current statement. They all jump out one or more nesting (scope) levels and they all (apart from continue) jump downwards. This restriction helps to avoid the goto "spaghetti code" syndrome inherent in old BASIC, FORTRAN and COBOL code2.

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



1- The most expensive part of exceptions is the actual creation of the exception object and its stacktrace. If you really, really need to use exception handling for "normal" flow control, you can either preallocate / reuse the exception object, or create a custom exception class that overrides the fillInStackTrace()method. The downside is that the exception's printStackTrace()methods won't give you useful information ... should you ever need to call them.

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

2 - The spaghetti code syndrome spawned the structured programmingapproach, where you limited in your use of the available language constructs. This could be applied to BASIC, Fortranand COBOL, but it required care and discipline. Getting rid of gotoentirely was a pragmatically better solution. If you keep it in a language, there is always some clown who will abuse it.

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

回答by Pascal Thivent

Just for fun, hereis a GOTO implementation in Java.

只是为了好玩,这里是 Java 中的 GOTO 实现。

Example:

   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 }

Running it:

$ java -cp bin:asm-3.1.jar GotoClassLoader GotoDemo           
   3
   2
   1
   0
   Hello World!

例子:

   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!

Do I need to add "don't use it!"?

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

回答by code lover

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);
    }

回答by Lukas Eder

While some commenters and downvoters argue that this isn't goto, the generated bytecode from the below Java statements really suggests that these statements really do express gotosemantics.

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

Specifically, the do {...} while(true);loop in the second example is optimised by Java compilers in order not to evaluate the loop condition.

具体来说,do {...} while(true);第二个示例中的循环由 Java 编译器优化,以便不评估循环条件。

Jumping forward

向前跳跃

label: {
  // do stuff
  if (check) break label;
  // do more stuff
}

In bytecode:

在字节码中:

2  iload_1 [check]
3  ifeq 6          // Jumping forward
6  ..

Jumping backward

向后跳

label: do {
  // do stuff
  if (check) continue label;
  // do more stuff
  break label;
} while(true);

In bytecode:

在字节码中:

 2  iload_1 [check]
 3  ifeq 9
 6  goto 2          // Jumping backward
 9  ..

回答by android.weasel

StephenC writes:

斯蒂芬C写道:

There are two constructs that allow you to do some of the things you can do with a classic goto.

有两种结构可以让您执行一些可以使用经典 goto 执行的操作。

One more...

多一个...

Matt Wolfe writes:

马特沃尔夫写道:

People always talk about never using a goto, but I think there is a really good real world use case which is pretty well known and used.. That is, making sure to execute some code before a return from a function.. Usually its releasing locks or what not, but in my case I'd love to be able to jump to a break right before the return so I can do required mandatory cleanup.

人们总是谈论从不使用 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

http://docs.oracle.com/javase/tutorial/essential/exceptions/finally.html

The finally block always executes when the try block exits. This ensures that the finally block is executed even if an unexpected exception occurs. But finally is useful for more than just exception handling — it allows the programmer to avoid having cleanup code accidentally bypassed by a return, continue, or break. Putting cleanup code in a finally block is always a good practice, even when no exceptions are anticipated.

finally 块总是在 try 块退出时执行。这确保即使发生意外异常也能执行 finally 块。但 finally 不仅仅用于异常处理——它允许程序员避免通过 return、continue 或 break 意外绕过清理代码。将清理代码放在 finally 块中始终是一个好习惯,即使没有预料到异常也是如此。

The silly interview question associated with finally is: If you return from a try{} block, but have a return in your finally{} too, which value is returned?

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

回答by mahasam

Try the code below. It works for me.

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

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++) {"

回答by ratchet freak

The easiest is:

最简单的是:

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;
    }
}

回答by apoorva

Use a labeled break as an alternative to goto.

使用带标签的中断作为转到的替代方法。