问题1:

为什么下面的代码编译时没有返回语句?

public int a() {
    while(true);
}

注意:如果我在while之后添加return,那么我会得到一个不可达代码错误。

问题2:

另一方面,为什么下面的代码编译,

public int a() {
    while(0 == 0);
}

尽管下面的内容没有。

public int a(int b) {
    while(b == b);
}

当前回答

问题1: 为什么下面的代码编译时没有返回语句? 公共int a() { 而(真正的); }

这是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总是true),所以它知道函数不能“正常返回”(删除函数体的末尾),因此没有返回是可以接受的。

问题2: 另一方面,为什么下面的代码编译, 公共int a() { While (0 == 0); } 尽管下面的内容没有。 公共int a(int b) { While (b == b); }

在0 == 0的情况下,编译器知道循环永远不会终止(0 == 0将永远为真)。但它不知道对于b == b。

为什么不呢?

编译器理解常量表达式(§15.28)。引用§15.2 -表达形式(因为奇怪的是这句话不在§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. We can 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 point for 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.

因此,由于它不“确定”表达式,编译器不知道循环永远不会终止,因此它认为方法可以正常返回——这是不允许的,因为它被要求使用return。所以它抱怨缺乏回报。

其他回答

问题1: 为什么下面的代码编译时没有返回语句? 公共int a() { 而(真正的); }

这是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总是true),所以它知道函数不能“正常返回”(删除函数体的末尾),因此没有返回是可以接受的。

问题2: 另一方面,为什么下面的代码编译, 公共int a() { While (0 == 0); } 尽管下面的内容没有。 公共int a(int b) { While (b == b); }

在0 == 0的情况下,编译器知道循环永远不会终止(0 == 0将永远为真)。但它不知道对于b == b。

为什么不呢?

编译器理解常量表达式(§15.28)。引用§15.2 -表达形式(因为奇怪的是这句话不在§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. We can 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 point for 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.

因此,由于它不“确定”表达式,编译器不知道循环永远不会终止,因此它认为方法可以正常返回——这是不允许的,因为它被要求使用return。所以它抱怨缺乏回报。

将方法返回类型视为不返回指定类型值的承诺,而是不返回非指定类型值的承诺,这可能很有趣。因此,如果你从未归还任何东西,你就没有违反承诺,因此以下任何一项都是合法的:

永远循环: X foo() { (,); } 递归下去: X foo() { 返回foo (); } 抛出异常: X foo() { throw new Error(); }

(我发现递归是一个有趣的思考:编译器认为该方法将返回一个类型为X的值(不管那是什么),但这不是真的,因为没有任何代码显示如何创建或获取X。)

查看字节代码,如果返回的内容与定义不匹配,则会收到一个编译错误。

例子:

For(;;)将显示字节码:

L0
    LINENUMBER 6 L0
    FRAME SAME
    GOTO L0

注意,没有返回字节码

它不会返回,因此不会返回错误的类型。

为了进行比较,可以使用如下方法:

public String getBar() { 
    return bar; 
}

将返回以下字节码:

public java.lang.String getBar();
    Code:
      0:   aload_0
      1:   getfield        #2; //Field bar:Ljava/lang/String;
      4:   areturn

注意“areturn”的意思是“返回一个引用”

现在如果我们这样做:

public String getBar() { 
    return 1; 
}

将返回以下字节码:

public String getBar();
  Code:
   0:   iconst_1
   1:   ireturn

现在我们可以看到定义中的类型与ireturn的返回类型不匹配,这意味着返回int。

所以归根结底,如果方法有返回路径,这个路径必须匹配返回类型。但是字节码中有一些实例根本没有生成返回路径,因此没有违反规则。