Java 案例的细节(可能与 C# 案例非常相似)与 Java 编译器如何确定方法是否能够返回有关。
具体来说,规则是根据JLS 8.4.7,具有返回类型的方法必须不能正常完成,而必须总是突然完成(此处突然通过 return 语句或异常表示)。
如果将方法声明为具有返回类型,则如果方法的主体可以正常完成,则会发生编译时错误。换句话说,具有返回类型的方法必须仅通过使用提供值返回的 return 语句返回;不允许“掉头”。
编译器会根据 JLS 14.21 Unreachable Statements 中定义的规则查看是否可以正常终止,因为它还定义了正常完成的规则。
值得注意的是,unreachable statements 的规则为具有定义true
常量表达式的循环创建了一个特殊情况:
当以下至少一项为真时,while 语句可以正常完成:
因此,如果while
语句可以正常完成,那么它下面的 return 语句是必要的,因为代码被认为是可达的,任何while
没有可达的 break 语句或常量表达式的循环true
都被认为能够正常完成。
这些规则意味着你的while
语句带有一个常量真表达式并且没有 a永远不会被认为break
是正常完成的,因此它下面的任何代码都不会被认为是可达的。方法的结尾在循环下方,并且由于循环下方的所有内容都是不可达的,因此方法的结尾也是如此,因此该方法可能无法正常完成(这是编译器所寻找的)。
if
另一方面,语句没有关于提供给循环的常量表达式的特殊豁免。
比较:
// I have a compiler error!
public boolean testReturn()
{
final boolean condition = true;
if (condition) return true;
}
和:
// I compile just fine!
public boolean testReturn()
{
final boolean condition = true;
while (condition)
{
return true;
}
}
区别的原因非常有趣,并且是由于希望允许不会导致编译器错误的条件编译标志(来自 JLS):
人们可能期望 if 语句以下列方式处理:
如果以下至少一项为真,则 if-then 语句可以正常完成:
当 if-then 语句可达且条件表达式不是值为 false 的常量表达式时,则 then 语句可达。
如果 then 语句可以正常完成或 else 语句可以正常完成,则 if-then-else 语句可以正常完成。
这种方法与其他控制结构的处理是一致的。但是,为了方便将 if 语句用于“条件编译”目的,实际规则有所不同。
例如,以下语句会导致编译时错误:
while (false) { x=3; }
因为该语句x=3;
不可访问;但表面上类似的情况:
if (false) { x=3; }
不会导致编译时错误。优化编译器可能会意识到该语句x=3;
将永远不会被执行,并且可能会选择从生成的类文件中省略该语句的代码,但在x=3;
此处指定的技术意义上,该语句不被视为“不可访问”。
这种不同处理的基本原理是允许程序员定义“标志变量”,例如:
static final boolean DEBUG = false;
然后编写代码,例如:
if (DEBUG) { x=3; }
这个想法是应该可以将 DEBUG 的值从 false 更改为 true 或从 true 更改为 false,然后正确编译代码,而无需对程序文本进行其他更改。
为什么条件 break 语句会导致编译器错误?
正如循环可达性规则中所引用的,如果一个while循环包含一个可达性的break语句,它也可以正常完成。if
由于语句的then子句的可达性规则根本不考虑 the 的条件if
,因此这样的条件if
语句的then子句总是被认为是可达的。
如果break
是可达的,那么循环之后的代码也再次被认为是可达的。由于没有可到达的代码导致循环后突然终止,因此该方法被认为能够正常完成,因此编译器将其标记为错误。