以下代码在我的Eclipse中可以顺利编译:
final int j = 1/0;
// compiles fine!!!
// throws ArithmeticException: / by zero at run-time
Java的优点之一是它可以在代码编译时就防止许多“愚蠢的代码”(例如,"Five" instanceof Number
不能编译!)。因此,这个事实甚至没有产生警告就更加令人惊讶了。当你考虑到常量表达式允许在编译时进行优化时,这种好奇心变得更加深了:
public class Div0 {
public static void main(String[] args) {
final int i = 2+3;
final int j = 1/0;
final int k = 9/2;
}
}
使用Eclipse编译,上面的代码片段生成以下字节码(javap -c Div0
)
Compiled from "Div0.java"
public class Div0 extends java.lang.Object{
public Div0();
Code:
0: aload_0
1: invokespecial #8; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_5
1: istore_1 // "i = 5;"
2: iconst_1
3: iconst_0
4: idiv
5: istore_2 // "j = 1/0;"
6: iconst_4
7: istore_3 // "k = 4;"
8: return
}
正如你所看到的,i
和 k
的赋值被优化为编译时常量,但除以0的操作(本应在编译时可检测到)仍然按原样编译。
javac 1.6.0_17
行为更加奇怪,会静默地进行编译,但完全将 i
和 k
的赋值从字节码中删除(可能是因为它确定了它们在任何地方都没有被使用),但保留了 1/0
(因为删除它将导致完全不同的程序语义)。
因此问题是:
-
1/0
是实际上可以在任何时间任何地方编译的合法Java表达式吗?- JLS 对此有什么说法?
- 如果这是合法的,是否有好的理由?
- 这可能有什么好处?