具有返回类型的 Java 方法在没有返回语句的情况下编译
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/31050114/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java method with return type compiles without return statement
提问by Willi Mentzel
Question 1:
问题 1:
Why does the following code compile without having a return statement?
为什么下面的代码编译时没有 return 语句?
public int a() {
while(true);
}
Notice: If I add return after the while then I get an Unreachable Code Error
.
注意:如果我在一段时间后添加 return ,那么我会得到一个Unreachable Code Error
.
Question 2:
问题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);
}
回答by T.J. Crowder
Question 1:
Why does the following code compile without having a return statement?
public int a() { while(true); }
问题 1:
为什么下面的代码编译时没有 return 语句?
public int a() { while(true); }
This is covered by JLS§8.4.7:
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?!"); } }
如果将方法声明为具有返回类型(第 8.4.5 节),并且该方法的主体可以正常完成(第 14.1 节),则会发生编译时错误。
换句话说,具有返回类型的方法必须仅通过使用提供值返回的 return 语句返回;该方法不允许“丢弃其主体的末端”。有关方法主体中 return 语句的精确规则,请参见第 14.17 节。
一个方法可能有一个返回类型但不包含返回语句。这是一个例子:
class DizzyDean { int pitch() { throw new RuntimeException("90 mph?!"); } }
Since the compiler knows that the loop will never terminate (true
is always true, of course), it knows the function cannot "return normally" (drop off the end of its body), and thus it's okay that there's no return
.
由于编译器知道循环永远不会终止(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); }
问题2:
另一方面,为什么下面的代码会编译,
public int a() { while(0 == 0); }
即使下面没有。
public int a(int b) { while(b == b); }
In the 0 == 0
case, the compiler knows that the loop will never terminate (that 0 == 0
will always be true). But it doesn'tknow that for b == b
.
在这种0 == 0
情况下,编译器知道循环永远不会终止(这0 == 0
总是正确的)。但它不知道对于b == b
.
Why not?
为什么不?
The compiler understands constant expressions (§15.28). Quoting §15.2 - Forms of Expressions(because oddly this sentence isn't in §15.28):
编译器理解常量表达式 (§15.28)。引用§15.2 - 表达式的形式(因为奇怪的是这句话不在 §15.28 中):
Some expressions have a value that can be determined at compile time. These are constant expressions(§15.28).
某些表达式具有可以在编译时确定的值。这些是常量表达式(第 15.28 节)。
In your b == b
example, because there is a variable involved, it isn't a constant expression and isn't specified to be determined at compilation time. Wecan see that it's always going to be true in this case (although if b
were a double
, as QBrute pointed out, we could easily be fooled by Double.NaN
, which is not ==
itself), but the JLS only specifies that constant expressions are determined at compile time, it doesn't allow the compiler to try to evaluate non-constant expressions. bayou.io raised a good pointfor why not: If you start going down the road of trying to determine expressions involving variables at compilation time, where do you stop? b == b
is obvious (er, for non-NaN
values), but what about a + b == b + a
? Or (a + b) * 2 == a * 2 + b * 2
? Drawing the line at constants makes sense.
在您的b == b
示例中,因为涉及一个变量,所以它不是一个常量表达式,也没有指定在编译时确定。我们可以看到,在这种情况下它总是为真(尽管如果b
是 a double
,正如 QBrute指出的,我们很容易被 愚弄Double.NaN
,这不是==
它本身),但 JLS 仅指定在编译时确定常量表达式,它不允许编译器尝试评估非常量表达式。bayou.io提出了一个很好的观点:如果你开始尝试在编译时确定涉及变量的表达式,你会在哪里停下来?b == b
很明显(呃,对于非NaN
值),但是呢a + b == b + a
?或者(a + b) * 2 == a * 2 + b * 2
?在常数处画线是有道理的。
So since it doesn't "determine" the expression, the compiler doesn't know that the loop will never terminate, so it thinks the method can return normally — which it's not allowed to do, because it's required to use return
. So it complains about the lack of a return
.
因此,由于它不“确定”表达式,编译器不知道循环永远不会终止,因此它认为该方法可以正常返回——这是不允许的,因为它需要使用return
. 所以它抱怨缺少一个return
.
回答by Boann
It can be interesting to think of a method return type not as a promise to return a value of the specified type, but as a promise notto return a value that is notof the specified type. Thus, if you never return anything, you are not breaking the promise, and so any of the following are legal:
它可以是有趣的,没想到一个方法的返回类型为承诺返回指定类型的值,而是一个承诺不返回的值是不指定类型的。因此,如果你从不返回任何东西,你就没有违背承诺,所以以下任何一项都是合法的:
Looping forever:
X foo() { for (;;); }
Recursing forever:
X foo() { return foo(); }
Throwing out an exception:
X foo() { throw new Error(); }
永远循环:
X foo() { for (;;); }
永远循环:
X foo() { return foo(); }
抛出异常:
X foo() { throw new Error(); }
(I find the recursion one fun to think about: The compiler believes that the method will return a value of type X
(whatever that is), but it isn't true, because there is no code present that has any idea how to create or procure an X
.)
(我发现递归思考起来很有趣:编译器认为该方法将返回一个类型的值X
(无论是什么),但事实并非如此,因为不存在任何知道如何创建或购买一个X
.)
回答by Philip Devine
Looking at the byte code, if what is being returned does not match the definition, you will receive a compile error.
查看字节码,如果返回的内容与定义不匹配,您将收到编译错误。
Example:
例子:
for(;;)
will show the bytecodes:
for(;;)
将显示字节码:
L0
LINENUMBER 6 L0
FRAME SAME
GOTO L0
Note the lack of any return bytecode
注意缺少任何返回字节码
This does not ever hit a return, and thus does not return the wrong type.
这永远不会返回,因此不会返回错误的类型。
For comparison, a method like:
为了比较,一个方法如下:
public String getBar() {
return bar;
}
Will return the following bytecodes:
将返回以下字节码:
public java.lang.String getBar();
Code:
0: aload_0
1: getfield #2; //Field bar:Ljava/lang/String;
4: areturn
Note the "areturn" which means "return a reference"
注意“areturn”,意思是“返回一个引用”
Now if we do the following:
现在,如果我们执行以下操作:
public String getBar() {
return 1;
}
Will return the following bytecodes:
将返回以下字节码:
public String getBar();
Code:
0: iconst_1
1: ireturn
Now we can see that the type in the definition does not match the return type of ireturn, which means return int.
现在我们可以看到定义中的类型与ireturn的返回类型不匹配,即return int。
So really what it comes down to is that if the method has a return path, that path must match the return type. But there are instances in the bytecode where no return path is generated at all, and thus no breaking of the rule.
所以归根结底是,如果该方法具有返回路径,则该路径必须与返回类型匹配。但是字节码中有一些实例根本没有生成返回路径,因此没有违反规则。