首页 文章

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

提问于
浏览
225

Question 1:

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

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

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

Question 2:

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

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

即使以下没有 .

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

3 回答

  • 274

    问题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 normally"(从它的主体的末尾掉下来),因此's okay that there'不是 return .

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

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

    为什么不?

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

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

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

    所以,因为它不知道循环永远不会终止,所以它认为该方法可以正常返回 - 它需要使用 return . 所以它抱怨缺乏 return .

  • 8

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

    • 永远循环:
    X foo() {
        for (;;);
    }
    
    • 永远递归:
    X foo() {
        return foo();
    }
    
    • 抛出异常:
    X foo() {
        throw new Error();
    }
    

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

  • 33

    查看字节代码,如果返回的内容与定义不匹配,您将收到编译错误 .

    Example:

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

    L0
        LINENUMBER 6 L0
        FRAME SAME
        GOTO L0
    

    Note the lack of any return bytecode

    这不会返回,因此不会返回错误的类型 .

    为了比较,一种方法如下:

    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 .

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

相关问题