Wil*_*zel 227 java syntax compilation return while-loop
问题1:
为什么以下代码在没有return语句的情况下编译?
public int a() {
while(true);
}
Run Code Online (Sandbox Code Playgroud)
注意:如果我在一段时间后添加返回,那么我得到一个Unreachable Code Error
.
问题2:
另一方面,为什么以下代码编译,
public int a() {
while(0 == 0);
}
Run Code Online (Sandbox Code Playgroud)
即使以下没有.
public int a(int b) {
while(b == b);
}
Run Code Online (Sandbox Code Playgroud)
T.J*_*der 274
问题1:
为什么以下代码在没有return语句的情况下编译?
Run Code Online (Sandbox Code Playgroud)public int a() { while(true); }
这由JLS§8.4.7涵盖:
如果声明方法具有返回类型(第8.4.5节),则如果方法的主体可以正常完成(第14.1节),则会发生编译时错误.
换句话说,具有返回类型的方法必须仅使用提供值返回的return语句返回; 该方法不允许"掉落其身体的末端".有关方法体中返回语句的精确规则,请参见§14.17.
方法可能具有返回类型但不包含return语句.这是一个例子:
Run Code Online (Sandbox Code Playgroud)class DizzyDean { int pitch() { throw new RuntimeException("90 mph?!"); } }
由于编译器知道循环永远不会终止(true
当然总是如此),它知道函数不能"正常返回"(从它的主体的末端掉下来),因此没有问题return
.
问题2:
另一方面,为什么以下代码编译,
Run Code Online (Sandbox Code Playgroud)public int a() { while(0 == 0); }
即使以下没有.
Run Code Online (Sandbox Code Playgroud)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
.
Boa*_*ann 33
它可以是有趣的,没想到一个方法的返回类型为承诺返回指定类型的值,而是一个承诺不返回的值是不指定类型的.因此,如果您从未退货,那么您并没有违背承诺,因此以下任何一项都是合法的:
永远循环:
X foo() {
for (;;);
}
Run Code Online (Sandbox Code Playgroud)永远递归:
X foo() {
return foo();
}
Run Code Online (Sandbox Code Playgroud)抛出异常:
X foo() {
throw new Error();
}
Run Code Online (Sandbox Code Playgroud)(我发现递归是一个有趣的思考:编译器认为该方法将返回一个类型的值X
(无论是什么),但它不是真的,因为没有代码存在任何想法如何创建或采购X
.)
查看字节代码,如果返回的内容与定义不匹配,您将收到编译错误.
例:
for(;;)
将显示字节码:
L0
LINENUMBER 6 L0
FRAME SAME
GOTO L0
Run Code Online (Sandbox Code Playgroud)
注意缺少任何返回字节码
这不会返回,因此不会返回错误的类型.
为了比较,一种方法如下:
public String getBar() {
return bar;
}
Run Code Online (Sandbox Code Playgroud)
将返回以下字节码:
public java.lang.String getBar();
Code:
0: aload_0
1: getfield #2; //Field bar:Ljava/lang/String;
4: areturn
Run Code Online (Sandbox Code Playgroud)
注意"areturn",意思是"返回参考"
现在,如果我们执行以下操作:
public String getBar() {
return 1;
}
Run Code Online (Sandbox Code Playgroud)
将返回以下字节码:
public String getBar();
Code:
0: iconst_1
1: ireturn
Run Code Online (Sandbox Code Playgroud)
现在我们可以看到定义中的类型与ireturn的返回类型不匹配,这意味着返回int.
所以它真正归结为如果该方法具有返回路径,则该路径必须与返回类型匹配.但是在字节码中有些实例根本没有生成返回路径,因此没有违反规则.