返回类型的Java方法编译时没有return语句

问题

问题1:
为什么以下代码在没有return语句的情况下编译?

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

注意:如果我在一段时间后添加返回,那么我得到aUnreachable Code Error

问题2:

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

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

即使以下没有。

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

#1 热门回答(272 赞)

问题1:为什么以下代码在没有return语句的情况下编译? public int a()
{
    而(真);
}

这包括在JLS§8.4.7中:

如果声明方法具有返回类型(第8.4.5节),则如果方法体可以正常完成(第14.1节),则会发生编译时错误。换句话说,具有返回类型的方法必须仅使用提供值返回的return语句返回;该方法不允许"掉落其身体的末端"。有关方法体中返回语句的准确规则,请参见§14.17。方法可能具有返回类型但不包含return语句。这是一个例子:class DizzyDean {
    int pitch(){throw new RuntimeException("90 mph?!"); }
}

由于编译器知道循环永远不会终止(当然,true总是为真),它知道函数不能"正常返回"(掉落它的主体的末尾),因此可以没有return

问题2:另一方面,为什么以下代码编译,public int a()
{
    而(0 == 0);
}
 即使以下没有。 public int a(int b)
{
    而(b == b);
}

0 == 0中,编译器知道循环永远不会终止(即0 == 0将始终为真)。但it并没有知道那个b == b

为什么不?

编译器了解constant expressions (§15.28)。 Quoting§15.2 - Forms of Expressions(因为奇怪的是这句话不在§15.28中):

某些表达式具有可在编译时确定的值。这些是常量表达式(§15.28)。

在你的b == b示例中,因为涉及一个变量,它不是一个常量表达式,并且未指定在编译时确定.我们可以看到它在这种情况下总是会成立(尽管ifb是adouble,如QBrutepointed out ,我们很容易被Double.NaN(isnot==自己)欺骗,但是JLS只指定在编译时确定常量表达式,它不允许编译器尝试计算非常量表达式。 bayou.ioraised a good point为什么不:如果你开始沿着试图在编译时确定涉及变量的表达式的道路,你在哪里停止?b == b很明显(呃,对于非NaN值),但是什么关于a + b == b + a? Or(a + b) * 2 == a * 2 + b * 2?在常量上绘制线条是有道理的。

因此,由于它没有"确定"表达式,编译器不知道循环将永远不会终止,因此它认为该方法可以正常返回 - 这是不允许的,因为它需要使用2826101052。所以它抱怨缺乏areturn


#2 热门回答(32 赞)

将方法返回类型视为返回指定类型的值的承诺,但作为promisenotto返回不是指定类型的值,可能会很有趣。因此,如果你从未退货,那么你并没有违背承诺,因此以下任何一项都是合法的:

  • 永远循环:X foo(){
        for(;;);
    }
  • 永远递归:X foo(){
        return foo();
    }
  • 抛出异常:X foo(){
        抛出新的错误();
    }

(我发现递归是一个有趣的思考:编译器认为该方法将返回typeX的值(无论是什么),但事实并非如此,因为没有代码存在任何想法如何创建或采购anX。)


#3 热门回答(8 赞)

查看字节代码,如果返回的内容与定义不匹配,则会收到编译错误。
示例:
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。

所以它真正归结为如果该方法具有返回路径,则该路径必须与返回类型匹配。但是在字节码中有些实例根本没有生成返回路径,因此没有违反规则。