【问题标题】:Why doesn't a Java constant divided by zero produce compile time error? [duplicate]为什么 Java 常量除以零不会产生编译时错误? [复制]
【发布时间】:2011-06-26 04:57:24
【问题描述】:

可能重复:
Is 1/0 a legal Java expression?

为什么这段代码会编译?

class Compiles {
    public final static int A = 7/0;
    public final static int B = 10*3;

    public static void main(String[] args) {}
}

如果我查看编译后的类文件,我可以看到 B 已被评估为 30,而 A 仍然是 7/0。

据我了解 JSL,除以零的表达式不是常数。

参考:JLS 15.28

我上面的陈述是由于这一行:

编译时常量表达式是表示原始类型值的表达式

因此除以零不会计算为原始值。

我真正不明白的是为什么编译器仍然允许这样做?为了清楚起见,我上面的代码使用“java.lang.ExceptionInInitializerError”使运行时崩溃

在我看来,编译器会威胁将任何最终静态变量作为常量并评估它的编译时间。这意味着编译器已经尝试评估 A,但由于它是除以零,它就让它通过。没有编译时错误。但这似乎非常非常奇怪......编译器知道它是除以零并且它会导致运行时崩溃,但它不会标记编译错误!

谁能给我解释一下为什么?

【问题讨论】:

  • 是否有任何除以零的实例会产生编译时错误?如果你在正常的程序代码中除以零,你会在运行时得到一个ArithmeticException,所以我认为这通过编译器也没什么奇怪的。

标签: java constants compile-time-constant jls constant-expression


【解决方案1】:

抛出java.lang.ExceptionInInitializerError 是唯一正确的行为。

如果您的代码没有编译,那么一个完全有效的 Java 程序就会被拒绝,这就是一个错误。

7/0 放入编译代码中的唯一正确替代方法实际上是显式抛出ExceptionInInitializerError,但这有多大用处?

编译器知道它是除以零,它会导致运行时崩溃,但它确实会标记编译错误!

实际上,我不同意……这个程序会崩溃吗?

class Compiles {
    public final static int A = 7/0;
    public final static int B = 10*3;

    public static void main(String[] args) {}

}

public class Test {

    // Application entry point.
    public static void main(String[] args) {
        try {
            new Compiles();

            launchTheMissiles();

        } catch (ExceptionInInitializerError e) {

            doUsefulStuff();

        }
    }
}

【讨论】:

  • 您的程序不会崩溃。但我的会。所以你总是将新对象的初始化放在 try/catch 中??
  • 是的。我总是将 try/catch 放在 ExceptionInitializerError-classes 的实例化周围。 ;-D
  • 按照这个逻辑,根本不应该有编译时错误,因为你可以用 try-catch 括起任何语句。这是一个公平的评估吗?
  • @Allohvk,我不清楚这将如何工作。像aoeu]aoeu(ueao 这样的异常会抛出什么异常? Eclipse 编译器可以compile it to throw an Error 但它仍然不是一个有效的Java 程序。形式化错误恢复将非常困难和复杂。实际错误何时结束,catch 子句从哪里开始?例如,这是否是一个可接受的 Java 程序:try{ao]/*%+^/eu}catch}}catch(Error e){}
  • 好的,是的,你是对的。因此,您可以将您之前的评论改写为“按照这种逻辑,syntactically valid 程序应该没有编译时错误。” (这显然是不可取的。)所以我同意,这里有一个中间立场,没有什么可以阻止创建者禁止7/0
【解决方案2】:

JLS 15.28 Constant Expression:

编译时常量表达式是表示原始类型值或字符串的表达式不会突然完成,并且仅使用以下内容组成:

...

因此,7/0 不是编译时常量,因为它的求值由于被零除而突然完成。因此,它被视为常规运行时表达式,并在运行时引发异常。

【讨论】:

  • 我就是这么说的!我完全同意。但我觉得奇怪的是它没有将其标记为编译错误,因为编译器已经评估了表达式?
  • 如果您同意它不是 compile-time 常量,那么您不应该对评估推迟到 runtime 感到惊讶,并因此引发异常。
  • 这可能是一个补丁来证明现有 javac 行为的合理性(由于向后兼容性,无法更改它)。规范可以说得很好:“等等等等,如果表达式不计算,那就是编译时错误
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-22
  • 1970-01-01
  • 1970-01-01
  • 2021-08-18
  • 1970-01-01
  • 2012-01-03
  • 1970-01-01
相关资源
最近更新 更多