Question 1:
Why does the following code compile without having a return statement?
public int a()
{
while(true);
}
这是由JLS§8.4.7覆盖的:
If a method is declared to have a return type (§8.4.5), then a compile-time error occurs if the body of the method can complete normally (§14.1).
In other words, a method with a return type must return only by using a return statement that provides a value return; the method is not allowed to "drop off the end of its body". See §14.17 for the precise rules about return statements in a method body.
It is possible for a method to have a return type and yet contain no return statements. Here is one example:
class DizzyDean {
int pitch() { throw new RuntimeException("90 mph?!"); }
}
编译器知道循环永远不会终止(当然,true
总是为真),因此它知道函数不能“正常返回”(从其主体中掉出末尾),因此没有 return
也是可以的。
Question 2:
On the other hand, why does the following code compile,
public int a()
{
while(0 == 0);
}
even though the following does not.
public int a(int b)
{
while(b == b);
}
在
0 == 0
的情况下,编译器知道循环永远不会终止(即
0 == 0
将始终为真)。但是对于
b == b
,它
不知道。
为什么呢?
编译器理解
常量表达式(§15.28)。引用
§15.2 - 表达式的形式(因为奇怪地这句话不在§15.28中):
一些表达式具有可以在编译时确定的值。这些是 常量表达式(§15.28)。
在您的
b == b
示例中,由于涉及变量,它不是一个常量表达式,也没有指定在编译时确定。我们可以看到在这种情况下它总是成立的(尽管如果
b
是
double
,就像QBrute指出的那样,我们可能会被
Double.NaN
欺骗,因为它本身不是
==
),但JLS只规定常量表达式在编译时确定,它不允许编译器尝试评估非常量表达式。bayou.io提出了一个很好的观点:如果您开始沿着在编译时确定涉及变量的表达式的道路走下去,您会在哪里停止?对于常量来划分界限是有意义的,
b == b
是显而易见的(对于非
NaN
值),但是
a + b == b + a
呢?或者
(a + b) * 2 == a * 2 + b * 2
?
因为它并未“确定”表达式,编译器不知道循环永远不会终止,因此它认为该方法可以正常返回——但实际上它不能这样做,因为必须使用
return
。所以编译器会抱怨缺少
return
。