1/0是合法的Java表达式吗? [英] Is 1/0 a legal Java expression?
问题描述
以下在我的Eclipse中编译正常:
final int j = 1/0;
//编译好!!!
//抛出ArithmeticException:/在运行时为零
Java防止了许多哑巴代码从第一个位置开始编译(例如Fiveinstanceof 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
)
编译自Div0.java
public class Div0 extends java.lang.Object {
public Div0();
代码:
0:aload_0
1:invokespecial#8; //方法java / lang / Object。< init>:()V
4:return
public static void main(java.lang.String []);
代码:
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:返回
}
如您所见, i
和 k
赋值被优化为编译时常量,但除以 0
(必须在编译时可以检测到)只是按原样编译。
javac 1.6.0_17
表现得更奇怪,无声编译但是将作业完全删除 i
和 k
字节码(可能是因为它确定它们没有在任何地方使用),但保留 1/0
完整(因为删除它会导致完全不同的程序语义)。 / p>
所以问题是:
-
1 / 0
实际上是一个合法的Java表达式,应该随时随地编译?
- JLS对此有何评价?
- 如果这样是合法的,有充分的理由吗?
- 这有什么用呢?
1/0
实际上是一个合法的Java表达式应该随时随地编译吗?
是。
JLS是什么怎么说呢?
没有什么特别的......除了说除以零将导致运行时异常。但是,JLS在以下定义中承认运行时异常的可能性:
编译时常量表达式是表示值的表达式原始类型或字符串不突然完成,仅使用以下内容组成:...
(重点补充。)所以以下内容不会编译:
switch(i){
case 1 :
case 1 + 1:
case 1/0://编译错误。
}
如果这是合法的,是否有好处原因呢?
好问题。我想这是一种抛出 ArithmeticException
的方法,尽管这不是一个合理的理由。以这种方式指定Java的一个更可能的原因是为了避免JLS和编译器中不必要的复杂性来处理很少会让人咬人的边缘情况。
但是这个一切都在旁边。事实是 1/0
是有效的Java代码,并且没有Java编译器应该将此标记为编译错误。 (如果有一个编译器开关将其关闭,那么Java编译器发出警告是合理的。)
The following compiles fine in my Eclipse:
final int j = 1/0;
// compiles fine!!!
// throws ArithmeticException: / by zero at run-time
Java prevents many "dumb code" from even compiling in the first place (e.g. "Five" instanceof Number
doesn't compile!), so the fact this didn't even generate as much as a warning was very surprising to me. The intrigue deepens when you consider the fact that constant expressions are allowed to be optimized at compile time:
public class Div0 {
public static void main(String[] args) {
final int i = 2+3;
final int j = 1/0;
final int k = 9/2;
}
}
Compiled in Eclipse, the above snippet generates the following bytecode (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
}
As you can see, the i
and k
assignments are optimized as compile-time constants, but the division by 0
(which must've been detectable at compile-time) is simply compiled as is.
javac 1.6.0_17
behaves even more strangely, compiling silently but excising the assignments to i
and k
completely out of the bytecode (probably because it determined that they're not used anywhere) but leaving the 1/0
intact (since removing it would cause an entirely different program semantics).
So the questions are:
- Is
1/0
actually a legal Java expression that should compile anytime anywhere?- What does JLS say about it?
- If this is legal, is there a good reason for it?
- What good could this possibly serve?
Is
1/0
actually a legal Java expression that should compile anytime anywhere?
Yes.
What does JLS say about it?
Nothing specific ... apart from saying that division by zero will result in a runtime exception. However, the JLS acknowledges that possibility of runtime exceptions in the following definition:
"A compile-time constant expression is an expression denoting a value of primitive type or a String that does not complete abruptly and is composed using only the following: ..."
(Emphasis added.) So the following would NOT compile:
switch(i) {
case 1:
case 1 + 1:
case 1 / 0: // compilation error.
}
If this is legal, is there a good reason for it?
Good question. I suppose that it is a way to throw ArithmeticException
though that is hardly a plausible reason. A more likely reason for specifying Java this way is to avoid unnecessary complexity in the JLS and compilers to deal with an edge case that is rarely going to bite people.
But this is all by the by. The fact is that 1/0
is valid Java code, and no Java compiler should ever flag this as a compilation error. (It would be reasonable for a Java compiler to issue a warning, provided that there was a compiler switch to turn it off.)
这篇关于1/0是合法的Java表达式吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!