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

时间:2015-06-25 12:14:57

标签: java syntax while-loop compilation return

问题1:

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

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

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

问题2:

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

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

即使以下情况没有。

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

3 个答案:

答案 0 :(得分:274)

  

问题1:

     

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

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

这由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() 
{
    while(0 == 0);
}
     

即使以下情况没有。

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

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

为什么不呢?

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

  

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

b == b示例中,因为涉及变量,所以它不是常量表达式,并且未指定在编译时确定。 我们可以看到在这种情况下总是如此(尽管如果bdouble,而QBrute pointed out,我们很容易被愚弄Double.NaNnot == itself),但JLS仅指定在编译时确定常量表达式,它不允许编译器尝试计算非常量表达式。 bayou.io raised a good point为什么不:如果你开始在编译时试图确定涉及变量的表达式,你会在哪里停止? b == b显而易见(呃,对于非NaN值),但是a + b == b + a呢?还是(a + b) * 2 == a * 2 + b * 2?在常数处绘制线条是有道理的。

因为它没有“确定”表达式,所以编译器不知道循环永远不会终止,因此它认为该方法可以正常返回 - 这是不允许的,因为它需要使用{ {1}}。所以它抱怨缺少return

答案 1 :(得分:33)

将方法返回类型视为返回指定类型的值的承诺,但作为承诺而不是返回不<的值,可能会很有趣指定类型的/ em>。因此,如果你永远不会退货,你就不会违背承诺,所以以下任何一种都是合法的:

  1. 永远循环:

    X foo() {
        for (;;);
    }
    
  2. 永远递归:

    X foo() {
        return foo();
    }
    
  3. 抛出异常:

    X foo() {
        throw new Error();
    }
    
  4. (我发现递归是一个有趣的思考:编译器认为该方法将返回类型X的值(无论是什么),但它不是真的,因为没有代码存在,知道如何创建或获得X。)

答案 2 :(得分: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

注意&#34; beturn&#34;这意味着&#34;返回参考&#34;

现在,如果我们执行以下操作:

public String getBar() { 
    return 1; 
}

将返回以下字节码:

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

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

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