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(…)
,因此