Question 1:
为什么以下代码在没有return语句的情况下编译?
public int a() {
while(true);
}
注意:如果我在一段时间后添加返回,那么我得到 Unreachable Code Error
.
Question 2:
另一方面,为什么以下代码编译,
public int a() {
while(0 == 0);
}
即使以下没有 .
public int a(int b) {
while(b == b);
}
3 回答
这由JLS§8.4.7涵盖:
由于编译器知道循环永远不会终止(当然,
true
总是为真),因此它知道函数不能"return normally"(从它的主体的末尾掉下来),因此's okay that there'不是return
.在
0 == 0
情况下,编译器知道循环永远不会终止(0 == 0
将永远为真) . 但是 doesn't 知道b == b
.为什么不?
编译器理解constant expressions (§15.28) . 引用§15.2 - Forms of Expressions(因为奇怪的是这句话不在§15.28中):
在您的
b == b
示例中,因为涉及一个变量,所以指定在编译时确定它是否为't a constant expression and isn't . We 可以看到它在这种情况下总是如此(尽管如果b
是double
,如QBrute pointed out,我们很容易被Double.NaN
愚弄,这是not == itself),但JLS只指定在编译时确定常量表达式时间,它不允许编译器尝试计算非常量表达式 . bayou.io raised a good point为什么不:如果你开始试图在编译时确定涉及变量的表达式,你会在哪里停止?b == b
是显而易见的(呃,对于非NaN
值),但a + b == b + a
怎么样?还是(a + b) * 2 == a * 2 + b * 2
?在常数处绘制线条是有道理的 .所以,因为它不知道循环永远不会终止,所以它认为该方法可以正常返回 - 它需要使用
return
. 所以它抱怨缺乏return
.将方法返回类型视为返回指定类型的值的承诺,但作为承诺不返回不是指定类型的值,可能会很有趣 . 因此,如果您从未退货,那么您并没有违背承诺,因此以下任何一项都是合法的:
(我发现递归是一个有趣的思考:编译器认为该方法将返回
X
类型的值(无论是什么),但事实并非如此,因为没有代码存在任何想法如何创建或者采购X
. )查看字节代码,如果返回的内容与定义不匹配,您将收到编译错误 .
Example:
for(;;)
将显示字节码:Note the lack of any return bytecode
这不会返回,因此不会返回错误的类型 .
为了比较,一种方法如下:
将返回以下字节码:
注意“areturn”,意思是“返回参考”
现在,如果我们执行以下操作:
将返回以下字节码:
现在我们可以看到定义中的类型与ireturn的返回类型不匹配,这意味着返回int .
所以它真正归结为如果该方法具有返回路径,则该路径必须与返回类型匹配 . 但是在字节码中有些实例根本没有生成返回路径,因此没有违反规则 .