Java中是否有goto语句?

289

我对此感到困惑。我们大多数人都被告知Java中没有goto语句。

但我发现它是Java中的关键字之一。它能在哪里使用?如果不能使用,那么为什么将其包含在Java中作为关键字?

我对此感到困惑。我们大多数人都被告知Java中没有goto语句。但我发现它是Java中的关键字之一。它在语法上有效,但Java编程规范建议不要使用它,因为过度或错误使用goto语句可能会导致代码变得难以理解和维护。所以,虽然Java允许使用goto语句,但实际上几乎所有的Java程序都避免使用它。


18
建议您永远不要使用goto这个关键字。 - lostiniceland
7
迪科斯彻大师说:“考虑到语句的转移在程序设计中被认为是有害的”。请看这里:https://dev59.com/nXVD5IYBdhLWcg3wOo9h - n00ki3
10
大家都知道“GOTO”是有害的,但这并不是问题的答案,对吗? - Martin Lazar
25
“g**o”一词在大多数编程语言中被视为淫秽,这是真正的原因。Java设计者只是在保护那些年轻无知的程序员免受腐败影响。( :-) ) - Stephen C
44
对goto的“巫狩”引发了我生命中最令人恼火的时刻之一。我见过人们通过在函数中隐藏功能、在多层嵌套循环中加入荒谬的退出逻辑以及以其他可能的方式进行各种过度设计,只是为了避免有人在代码审查中批评他们的代码。这个规则,以及“避免多次返回”的谬论,都是无稽之谈。有时使用goto会使事情变得不易维护,但也有时使用goto会使事情更易维护。我曾经非常希望这场“巫狩”能在80年代就结束。 - user4229245
显示剩余7条评论
23个回答

9

感谢上天,Java 中没有 goto

goto 关键字仅仅是被保留了而已,并未被使用(const 也是同样的情况)。


我可以知道这里的“reserved”是什么意思吗?如果在代码中使用goto和const不是一个好的实践,为什么它们被保留?你能解释一下吗? - Gopi
@Sri Kumar:请看@applechewer的回答,它存在但尚未实现。 - Valentin Rocher
1
@Sri Kumar:保留关键字可以防止它们被用作变量名或类似的用途。这样,这些关键字可以在未来的Java版本中实现,而不会破坏旧的源代码,否则可能会使用它们。 - Peter Di Cecco

7
不,尽管是保留字,但Java中没有使用goto。同样适用于const。这两者都用于C++,这可能是它们被保留的原因;意图很可能是为了避免将来从C++迁移到Java的程序员产生困惑,并且也保留了在后续Java版本中使用它们的选项。

1
我真的希望 goto 在不久的将来至少不被支持 ;) - Bozho
6
@Bozho:嗯,它可能被用于一些与那个不好的“有害”goto完全无关的巧妙新功能。 - Michael Borgwardt
支持goto语句将是程序方法学的巨大倒退。它因充分而充足的理由而被禁止,并且不需要存在。实际上,它没有必要存在。无论出于任何想象得到的原因。 - flounder
@flounder:我完全同意直接跳转到代码中任意点的功能性应该除了机器语言/汇编之外永远不再使用。但是关键字 goto 可能会因为其他更好的目的而被重新使用。 - Michael Borgwardt

5

是的,这是可能的,但不像在c#中一样好用(在我看来,c#更好!)。认为goto总是会使软件变得模糊和愚蠢的意见是无聊的和愚蠢的!遗憾的是Java至少没有类似于goto case xxx的功能。

前往跳转:

 public static void main(String [] args) {
   myblock: {
     System.out.println("Hello");
     if (some_condition)
       break myblock; 
     System.out.println("Nice day");
   }
   // here code continue after performing break myblock
   System.out.println("And work");
 }

跳转到后面:

 public static void main(String [] args) {
   mystart: //here code continue after performing continue mystart
   do {
     System.out.println("Hello");
     if (some_condition)         
       continue mystart; 
     System.out.println("Nice day");
   } while (false);
   System.out.println("And work");
 }

3

请注意,您可以通过以下方式替换大多数goto的良性用途:

  • return

  • break

  • break label

  • 在try-catch-finally中抛出异常


5
异常不应用于流程控制。 - ChssPly76
16
异常情况下确实会使用异常处理,但应该只在特殊情况下使用它们。例如,在 C 语言中,goto 的用途之一是错误处理,尤其是在需要清理时。 - starblue
2
@starblue,你说出了我的心声。抛出异常就是控制流。实际上,在C语言中,你可以通过setjmp/longjmp相对清晰地实现异常处理,只需确保首先setjmp到处理代码并在异常时执行longjmp()即可。 - user4229245
1
@WVrock 你可以尝试使用 return - Andrew Lazarus
1
@WVrock 您可以将要跳过的方法部分放在标签中(请参见此处),然后如果您发现不需要该部分,则中断标签。但是,您必须将条件逻辑放在标签内部,否则它将无法工作。 - Tech Expert Wizard
显示剩余5条评论

2
正如所指出的,Java 中没有 goto,但是该关键字被保留以防 Sun 有一天想要添加 goto 到 Java 中。他们希望能够在不破坏太多代码的情况下添加它,因此保留了该关键字。请注意,Java 5 中添加了 enum 关键字,也没有破坏太多的代码。
虽然 Java 没有 goto,但它有一些结构对应于一些使用 goto 的用法,即能够使用命名循环的 breakcontinue。此外,finally 可以被认为是一种扭曲的 goto

1

这被认为是绝对不应该做的事情之一,但可能将其列为保留字是为了避免开发人员的混淆。


1
禁止使用相同的变量名进行声明。
例如: int i = 0, goto;

3
为什么不行?为什么我们不被允许做这些声明? - ApproachingDarknessFish
D'Oh。为什么不能把变量命名为“for”或“else”?PL/1没有保留字,你可以写任何东西。 - flounder

1

这个链接没有明确指出goto何时被放逐到保留字的地下世界中,它只是说“未使用”。 - Tech Expert Wizard

1

6
这就好比说任何编程语言都有goto语句,因为在底层的汇编代码中存在无条件跳转。虽然字节码中有goto语句,但这并不意味着Java语言中也有goto语句,因为“在Java中”指的是“在Java语言中”,而字节码并不是源代码的一层。 - user4229245
@tgm1024,“在Java中”也可以解释为“在Java平台上”。Java编译器需要生成Java字节码,否则输出将无法在Java平台JVM上工作。例如,C++不指定编译输出,编译器可以自由地生成任何形式的机器代码(或任何其他代码)。使用Java字节码编程的应用程序可以称为“Java应用程序”,但使用机器代码编程的应用程序不能称为“C++应用程序”。 - Lindlof
2
我非常清楚什么是Java字节码。我在1996年开始编写Java代码。而且你可以让其他语言为JVM生成Java字节码。我要纠正你的是这个想法,即有两个源层。实际上并没有。你有Java源代码,它被编译成Java字节码(由JVM执行),这不是额外的源层。仅仅因为字节码中有一个“goto”,并不意味着Java中也有“goto”。Java有命名的break和continue,但没有goto。 - user4229245
@tgm1024 我被一个踩票吵醒了 :) 看起来我输掉了这场争论,因为你发表了最后一条评论,而且你的资历也很印象深刻。我的观点是,使用Java字节码进行编程是非常可能的。为了让你放心,这里甚至有一个关于这个问题的问题:https://dev59.com/iHA75IYBdhLWcg3ws7Yh - Lindlof
“使用Java字节码进行编程是非常可能的”,即使这是可能的(我们知道这是可能的,但无论如何),答案也与精确问题无关。 - user2587965

1
我不太喜欢使用goto,因为它通常会使代码变得难以阅读。但是,我相信在某些情况下有例外(尤其是在词法分析器和解析器方面!)
当然,您可以将程序转换成类似汇编语言的形式,并编写类似以下内容的内容来将其带入Kleene规范形式:
int line = 1;
boolean running = true;
while(running)
{
    switch(line++)
    {
        case 1: /* line 1 */
                break;
        case 2: /* line 2 */
                break;
        ...
        case 42: line = 1337; // goto 1337
                break;
        ...
        default: running = false;
                break;
    }
}

你基本上编写了一个虚拟机来执行你的二进制代码...其中line对应于指令指针。

这比使用goto的代码更易读,不是吗?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接