在Java中,`1/0`是一个常量表达式吗?

33
据我理解,根据Java 8 JLS文档(链接),表达式 (1/0) 被认为是常量表达式,但是当我尝试使用OpenJDK 8编译以下程序时,出现了错误。
public class Switch {
    public static void main(String[] args) {
        switch(42) {
            case (1/0):
                return;
            default:
                return;
        }
    }
}

错误显示(1/0)不是常量表达式。

Switch.java:4: error: constant expression required
            case (1/0):
                 ^
1 error

我有遗漏什么吗?还是OpenJDK 8中存在一个错误?


你期望输入哪个值来进入这个case?! - Biffen
你不能真的除以零。 - Svetlin Zarev
9
如果你做一些明智的事情,比如(1/2),它是否有效? - Armand
3
"1/0" 会抛出 "java.lang.ArithmeticException: / by zero"异常,这可能是导致该表达式不被视为表示的原因。 - Pshemo
8
相关链接:1/0在Java中是否是合法表达式?注:本翻译仅供参考,如有不准确之处,请以原文为准。 - sstan
显示剩余2条评论
2个回答

35
编译器正在执行常量折叠(预计算微不足道的文字表达式)。这种情况下,“突然完成”表达式,使用JLS术语,使其不符合“常量表达式”的定义。所以这不是一个bug,而是与JLS一致。
是的,这个表达式也不会评估出一个值(警告试图执行这样操作的用户结果将不是常量表达式),但编译器在尝试之前并不知道这一点。不评估为一个值和突然完成似乎是相辅相成的。
添加变量声明,例如:
int x = 1 / 0;

不会导致编译器错误,而是由于switch语句要求在编译时评估表达式。

顺便说一下,我检查了Oracle和IBM JDK的版本7,发现这种情况也发生了,不仅仅是OpenJDK或JDK8特有的。


7
是的,+1 是正确强调了 JLS 规范中“突然完成”部分的内容。 - sstan
@sstan 是的,我错过了常量表达式规范的那一部分! - ReyCharles

15

常量表达式必须能够计算出一个值,因为编译器必须将该表达式还原为一个值。

1/0 没有任何值。

参考JSL §15.28:

编译时常量表达式是指仅由以下内容组成的基本类型或字符串值表示且不会意外完成的表达式:


6
我认为重点应该放在“不突然中止”上,也就是不抛出java.lang.ArithmeticException异常! 发现得好,谢谢! - ReyCharles
这要看情况,因为关键在于如果它没有可评估的值,它会突然完成,而这种情况就是这种情况。"表示一个值"更多地与数学相关的限制,而突然完成则更多地是一种实用的限制。实际上,异常甚至没有被抛出,因为常量折叠是在编译时完成的,而不是在执行期间完成的,这是一个真正的特殊情况。 - Jack
1
相反,您可以说它没有值,因为它突然完成。 JLS非常清楚地说明了表达式何时会突然完成(例如整数除以零),而在定义表达式是/表示什么时,使用哪些表达式并不那么好。https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.6 - ReyCharles
不,它没有值,无论Java如何,因此评估突然完成的事实与给出该表达式一个值无关。https://en.wikipedia.org/wiki/Undefined_(mathematics) - Jack
3
在Java中,无论数学上如何,1.0/0.0都具有一个值。 - ReyCharles
1.0/0.0 之所以有一个值,只是因为数学赋予了它一个值,这与您所说的相反。而且,根据 §14.11 的规定,您不能使用浮点数:表达式的类型必须是 char、byte、short、int、Character、Byte、Short、Integer、String 或枚举类型(§8.9),否则会出现编译时错误。 否则,if (1.0f/0.0f == value) 是完全合法的。 - Jack

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接