Java 中 goto 语句的替代方案

发布于 2024-08-24 11:34:02 字数 70 浏览 10 评论 0原文

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

因为Java没有goto。

What is an alternative function for the goto keyword in Java?

Since Java does not have a goto.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

睫毛溺水了 2024-08-31 11:34:02

您可以使用带标签的 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 功能。

You could use a labeled BREAK statement:

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.

妥活 2024-08-31 11:34:02

Java 中没有任何与 goto 概念直接等效的东西。有一些结构可以让您执行一些使用经典的 goto 可以执行的操作。

  • breakcontinue 语句允许您跳出循环或 switch 语句中的块。
  • 带标签的语句和 break 允许您跳出任意复合语句到给定方法(或初始化块)内的任何级别。
  • 如果您为循环语句添加标签,则可以continue 从内循环继续外循环的下一次迭代。
  • 抛出和捕获异常允许您(有效地)跳出方法调用的多个级别。 (但是,异常的成本相对较高,并且被认为是执行“普通”控制流1的糟糕方法。)
  • 当然,还有返回

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


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

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

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

  • The break and continue statements 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.

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.


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.

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

九局 2024-08-31 11:34:02

只是为了好玩,这里是一个 GOTO 实现在爪哇。

示例:

 1 公共类 GotoDemo {
   2 公共静态无效主(字符串[] args){
   3 整数 i = 3;
   4 System.out.println(i);
   5 i = i - 1;
   6 如果 (i >= 0) {
   7 GotoFactory.getSharedInstance().getGoto().go(4);
   8}
   9         
  10 尝试{
  11 System.out.print("地狱");
  12 if (Math.random() > 0) throw new Exception();            
  13 System.out.println("世界!");
  14 } catch (异常 e) {
  15 系统.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
   你好世界!

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

Just for fun, here is a GOTO implementation in Java.

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!

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

吝吻 2024-08-31 11:34:02

虽然一些评论者和反对者认为这不是 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  ..

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 goto semantics.

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

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  ..
云裳 2024-08-31 11:34:02

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

您必须在块的范围内才能中断标签:

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

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

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

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.

阳光下的泡沫是彩色的 2024-08-31 11:34:02
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);
    }
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);
    }
吻风 2024-08-31 11:34:02

斯蒂芬·C 写道:

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

还有一件事……

马特·沃尔夫写道:

人们总是谈论永远不要使用 goto,但我认为有一个
非常好的现实世界用例,这是众所周知和使用的。
也就是说,确保在从 a 返回之前执行一些代码
功能..通常是释放锁或其他什么,但就我而言,我会
喜欢能够在返回之前立即休息一下,这样我就可以做
需要强制清理。

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不仅仅对异常有用
处理——它允许程序员避免使用清理代码
意外地被返回、继续或中断绕过。放置清理
最后块中的代码始终是一个好习惯,即使没有
预计会有例外情况。

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

StephenC writes:

There are two constructs that allow you to do some of the things you
can do with a classic 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.

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

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.

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?

看轻我的陪伴 2024-08-31 11:34:02

最简单的是:

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

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;
    }
}
剧终人散尽 2024-08-31 11:34:02

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

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

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++) {"
山川志 2024-08-31 11:34:02

在现代 Java 中,我只使用 switch 和 String。我很惊讶我找不到这个答案:

for (String label = "start";;) {
    switch (label) {
        case "start":
           ...
        case "something":
           ...
        case "whatever":
           ...
           label = "something"; break; // <== those two commands equal goto
           ...
        default:
           return;
    }

}

In modern Java I would just use switch and String. I am surprised that I couldn't find this answer:

for (String label = "start";;) {
    switch (label) {
        case "start":
           ...
        case "something":
           ...
        case "whatever":
           ...
           label = "something"; break; // <== those two commands equal goto
           ...
        default:
           return;
    }

}
请止步禁区 2024-08-31 11:34:02

使用带标签的break 作为 goto 的替代方案。

Use a labeled break as an alternative to goto.

何必那么矫情 2024-08-31 11:34:02

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 行时,< strong>代码流程将从之前重新开始。

Java doesn't have goto, because it makes the code unstructured and unclear to read. However, you can use break and continue as civilized form of goto without its problems.


Jumping forward using 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");

Output:

Before Break
After ahead

Jumping backward using continue

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

This will result in an infinite loop as every time the line continue before is executed, the code flow will start again from before.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文