为什么即使在 System.exit(0) 之后也需要返回;

2022-09-01 06:29:03

考虑这个函数:

public boolean foo(){
   System.exit(1);
   //The lines beyond this will not be read
   int bar = 1;                  //L1
   //But the return statement is required for syntactically correct code
   return false;                 //L2

   //error here for unreachable code
   //int unreachable = 3;        //L3

}

有人可以解释为什么L1和L2明显无法访问没有给出警告,但L3却给出了警告。


答案 1

因为就编译器而言,只是另一个方法调用。System.exit()

它所做的是结束过程的事实只能从实现(这是本机代码,而不是它有任何区别)中找出来。

如果你必须输入你的代码(通常最好避免它,除非你想返回0以外的代码),它实际上应该在返回的方法中,例如。这样更好。System.exit()voidmain()

至于可访问性,解释是相同的:是Java语言的关键字,因此IDE使用的编译器或解析器可以看出,理论上不可能执行语句之后的代码。此处定义了这些规则。returnreturn


答案 2

Java 编译器对 . 一无所知。就它而言,这只是一种方法 - 因此可以到达语句的末尾。System.exit

这么说,并且“明显无法到达”,但这只是因为你知道什么。语言没有 - 而它确实知道语句的作用,所以它知道这真的是不可访问的。L1L2System.exitreturnL3

我有时认为能够声明一个方法不仅仅是,但永远不会正常终止是很有用的 - 它永远不会只是返回(尽管它可能会引发异常)。然后,编译器将能够使用该信息使任何调用表达式的结尾无法访问,从而防止此类事情成为问题。然而,这只是我对语言设计的梦想 - Java没有类似的东西,对于编译器来说,“知道”特定的JRE方法永远不会正常返回将是一个非常糟糕的主意,因为这个概念不能直接在语言中表达。void

相反,编译器受 JLS 第 14.21 节规则的约束,包括:

  • 非空块中不是开关块的第一个语句在可访问块的情况下是可访问的。
  • 非开关块的非空块中的所有其他语句 S 都可以访问,因为 S 前面的语句可以正常完成。

...

表达式语句可以在可访问的情况下正常完成。

(方法调用是表达式语句。

然后从第8.4.7节开始:

如果将方法声明为具有返回类型,则当方法的主体可以正常完成时时,将发生编译时错误 (§14.1)。

在14.1中:

除非另有指定,否则如果语句计算的所有表达式和它执行的所有子语句都正常完成,则该语句将正常完成。

所以调用 to 可以正常完成,就编译器而言,这意味着方法的主体可以正常完成,从而导致错误。System.exit()foo