1/0 是合法的 Java 表达式吗?
下面的代码在我的 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 对此有何评论?
- 如果这是合法的,是否有充分的理由?
- 这有什么好处?
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
是的。
没有什么具体的...除了说除以零会导致运行时异常。然而,JLS 在以下定义中承认运行时异常的可能性:
(添加了强调。)因此以下内容不会编译:
好问题。我认为这是抛出 ArithmeticException 的一种方法,尽管这不是一个合理的理由。以这种方式指定 Java 的一个更可能的原因是避免 JLS 和编译器中不必要的复杂性来处理很少会困扰人们的边缘情况。
但这都不是重点。事实是
1/0
>> 是 <<有效的 Java 代码,任何 Java 编译器都不应该将其标记为编译错误。(如果还有一种方法可以关闭警告,那么 Java 编译器发出警告是合理的。但另一方面,除以常量零的情况非常罕见,因此实现这一点的价值值得怀疑。)
Yes.
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:
(Emphasis added.) So the following would NOT compile:
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 beside the point. 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 also a way to turn off the warning. But the flipside that division by a constant zero is sufficiently rare as to make the value of implementing this doubtful.)
我深入研究了错误数据库,发现了一些有趣的信息。
错误 ID 4178182:JLS 未将 1/0 的行为指定为常量表达式
Bug ID 4089107:javac 处理整数除以(常量)零作为一个错误
错误 ID 4154563:javac 在 case 表达式中接受除以零的常量表达式。
结论
因此,
1/0
是否应该编译的问题是一个有争议的讨论话题,一些人引用 Guy Steele 的说法,声称这应该是一个编译时错误,而其他人则说它不应该' t。看来最终决定它既不是编译时错误也不是编译时常量。I did some digging into the Bug Database, and discovered some interesting information.
Bug ID 4178182: JLS doesnt specify behavior for 1/0 as a constant expression
Bug ID 4089107: javac treats integer division by (constant) zero as an error
Bug ID 4154563: javac accepts division by zero constant expressions in case expressions.
Conclusion
So the question of whether or not
1/0
should compile was a contested topic of discussion, with some people quoting Guy Steele claiming that this should be a compile time error, and others saying that it shouldn't. It seems that ultimately it's decided that it's neither a compile-time error nor a compile-time constant.那么,如果您查看 Double 类,您将看到以下内容:
在 Float 类中进行相同的计算,只不过使用浮点数而不是双精度数。基本上,1/0 返回一个非常非常大的数字,大于 Double.MAX_VALUE。
以下代码:
输出:
注意打印
Double.POSITIVE_INFINITY
时的特殊情况。它打印出一个字符串,尽管它被视为双精度。要回答这个问题,是的,它在 Java 中是合法的,但 1/0 解析为“无穷大”,并且与标准双精度数(或浮点数等)的处理方式不同。
我应该指出,我完全不知道它是如何或为什么以这种方式实现的。当我看到上面的输出时,这对我来说就像黑魔法。
Well, if you look into the Double class, you will see the following:
The same calculation is made in the Float class, except with floats instead of doubles. Basically, 1/0 returns a really, really big number, larger than Double.MAX_VALUE.
This following code:
Outputs:
Note the special case in printing out
Double.POSITIVE_INFINITY
. It prints out a string, though it's regarded as a double.To answer the question, yes it is legal in Java, but 1/0 resolves to "infinity" and is treated differently from standard Doubles (or floats, or so on and so forth).
I should note that I do not have the slightest clue how or why it was implemented this way. When I see the above output, it all seems like black magic to me.
Java 明确要求整数除以零触发 ArithmeticException。无法省略对
j
的分配,因为这会违反规范。Java explicitly requires integer division by zero to trigger an
ArithmeticException
. The assignment toj
can't be elided because that would violate the spec.这是合法的,因为没有任何地方规定编译器应该在编译时折叠常量表达式。
“智能”编译器可能会编译:
as
但没有任何内容表明编译器必须这样做。除此之外,1/0 是一个合法表达式,就像:
是一个合法表达式一样。
在运行时它会抛出异常,但这是一个运行时错误是有原因的。
It's legal because no where is it a given that the compiler is supposed to fold constant expressions at compile time.
A "smart" compiler might compile:
as
But there's nothing that says the compiler HAS to do that. Other than that, 1/0 is a legal expression just like:
is a legal expression.
At RUNTIME it throws an exception, but that's a runtime error for a reason.
当您无论如何都需要运行时变体时,为什么还要在编译时捕获它呢?
例如,如果您从文本文件加载并解析“0”,然后尝试除以它,Java 将不知道您在编译时做了什么,因为它不知道该外部文件的内容。
此外,如果要将任何变量设置为 0 并除以该变量,Java 必须跟踪脚本中每个点上每个变量的每个可能值,以便在编译时捕获除以 0 的情况。
不妨保持一致并使其成为仅运行时的异常。
Why bother catching this at compile-time, when you're going to need a run-time variant anyway?
For example, if you were loading and parsing "0" from a text file, then tried to divide by it, Java would have no idea what you were doing at compile-time because it doesn't know the contents of that external file.
Also if you were to set any variable to 0 and divide by the variable, Java would have to keep track of every possible value of every variable at every point in the script in order to catch a divide by 0 at compile time.
Might as well keep things consistent and make it a runtime-only exception.
从编译的角度来看是合法的,但是如果执行的话会抛出异常!
原因...良好的编程必须允许灵活性,因此您输入的所有表达式和每个代码都是编译器的变量,因此在数学表达式 X/Y 中,编译器不关心 Y 是否变量值是 (Y==0) 或编译器的任何其他数字,这是一个变量...如果编译器还必须查看值,那将被视为运行时,不会它。
It is legal in compiling point of view, but it would throw an exception if executed!
the reason... well programming must allow flexibility therefore all the expressions and every single code you type is a variable for the compiler, thus in the mathematical expression X/Y the compiler does not care if the Y variable value is (Y==0) or any other number for the compiler this is a variable... if the compiler would have to look at values also, that would be considered runtime, wouldn't it.
既然其他人已经回答了
1/0
的合法性,那么让我们转向第二个问题:答案可能是:
PS:它起作用了。 ;o)
Since others already answered the legality of
1/0
, let's move to the second question:An answer could be:
P.S.: It worked. ;o)