Java 为什么即使在系统退出(0)后仍需要返回;

Java 为什么即使在系统退出(0)后仍需要返回;,java,return,Java,Return,考虑这一功能: 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 //er

考虑这一功能:

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 Visible not-reachable不会发出警告,而L3会发出警告。

从语言的角度来看,只有两种方法可以跳出当前范围:
返回
抛出
。方法调用从未以相同的方式考虑,即使它们只包含一行代码:

void method() {
  throw new RuntimeException();
}
甚至更多。理论上,任何方法调用都可能导致抛出
RuntimeException
。在这种情况下,编译器可能会对不在
try
块中的任何方法调用发出警告:

...
method(); // WARNING: may throw in theory
anotherMethod(); // WARNING: possible unreachable code, also may throw
anotherMethod2(); // WARNING: possible unreachable code, also may throw
// etc
...

对于您的问题,逻辑是相同的。

Java编译器对
系统一无所知。退出
。就它而言,它只是一个方法——因此语句的结尾是可以到达的

您说
L1
L2
是“明显不可到达的”,但这只是因为您知道
System.exit
的作用。该语言不知道,但它确实知道
return
语句的作用,因此它知道
L3
实际上是不可访问的

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

相反,编译器受的规则约束,包括:

  • 非空块(不是开关块)中的第一条语句在该块可到达时是可到达的
  • 当S前面的语句可以正常完成时,非空块(不是开关块)中的其他语句S都是可访问的

如果表达式语句是可访问的,则它可以正常完成

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

然后从第8.4.7节:


如果一个方法被声明为具有返回类型,那么如果该方法的主体可以正常完成,则会发生编译时错误(§14.1)

在14.1中:

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


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

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

它所做的是结束流程,这一事实只能从实现中发现(这是本机代码,并不是说它有什么区别)


如果必须在代码中放入
System.exit()
(通常最好避免,除非您想返回一个非0的代码),那么它应该位于返回
void
main()
的方法中。那样更好


至于可达性,解释是一样的:
return
是Java语言的一个关键字,因此IDE使用的编译器或解析器可以告诉我们,理论上执行
return
语句之后的代码是不可能的。这些规则已定义。

静态代码分析工具可能未考虑应用程序正在终止

如果一个方法被声明为返回一个非void值,那么它必须在某个地方包含一个
return
语句,即使它从未到达(如问题中的代码中)

从编译器的角度来看,
System.exit()
只是另一个方法调用,没有什么特别的地方表明程序一到达就结束了。只有作为程序员的您知道这一事实——但这是编译器所不知道的


关于问题的第二部分-在方法内的代码块中,任何东西都不能在
return
语句之后执行,因为那永远是不可检查的代码。这就解释了为什么编译器会抱怨L3行。

编译器会检查某些代码是否只能通过return关键字(通常也包括throw和break(在循环的情况下))访问。对于编译器来说,exit方法调用只是另一个调用,它不知道它的含义,因此它不知道以后的代码将永远不会到达。

我知道这没有意义,当您调用方法时,Java编译器仍然是这样工作的
编译器此时不知道Sytem.exist是做什么的(从这个意义上讲,为什么rt.jar应该与编译时使用的其他jar不同?)
例如,这与下一段代码相反-

 public int test() {
  throw new NullPointerException("aaaa");
}
编译器可以判断总是抛出异常,因此不需要返回
Me:“在返回语句之后可以执行任何操作吗?”
爪哇:“没有。”

Me:“在我调用System.exit之后可以执行任何操作吗?”

Java:“这是一个方法,我不知道它是做什么的——它不是一个保留关键字,据我所知它不会影响程序流”(而且它甚至可能不工作(我不知道exit是否会抛出异常(或它的未来变体))

哪个编译器给出了这个警告?@Thorbjørnravandersen在中使用Java编译器eclipse@NitinChhajer,您正在使用Eclipse吗?没有人阻止您将
System.exit()
更改为NOP。现在,它可以抛出一个安全异常/或ThreadDeath。事实上,您甚至可以调用另一个方法
foo()
,该方法反过来调用
System.exit(…)
,因此