1/0 是合法的 Java 表达式吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2934063/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is 1/0 a legal Java expression?
提问by polygenelubricants
The following compiles fine in my Eclipse:
以下在我的 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 Numberdoesn'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:
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;
}
}
Compiled in Eclipse, the above snippet generates the following bytecode (javap -c Div0)
在 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
}
As you can see, the iand kassignments are optimized as compile-time constants, but the division by 0(which must've been detectable at compile-time) is simply compiled as is.
如您所见,i和k赋值被优化为编译时常量,但除法0(必须在编译时检测到)只是按原样编译。
javac 1.6.0_17behaves even more strangely, compiling silently but excising the assignments to iand kcompletely out of the bytecode (probably because it determined that they're not used anywhere) but leaving the 1/0intact (since removing it would cause an entirely different program semantics).
javac 1.6.0_17行为更奇怪,静默编译但将分配给字节码i并k完全从字节码中删除(可能是因为它确定它们不在任何地方使用)但保持1/0完整(因为删除它会导致完全不同的程序语义)。
So the questions are:
所以问题是:
- Is
1/0actually 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?
- 是
1/0实际上应该编译随时随地法律Java表达式?- JLS 对此有何评论?
- 如果这是合法的,是否有充分的理由?
- 这有什么好处呢?
采纳答案by Stephen C
Is
1/0actually a legal Java expression that should compile anytime anywhere?
是
1/0实际上应该编译随时随地法律Java表达式?
Yes.
是的。
What does JLS say about it?
JLS 对此有何评论?
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:
没什么特别的……除了说被零除会导致运行时异常。但是,JLS 在以下定义中承认运行时异常的可能性:
"A compile-time constant expression is an expression denoting a value of primitive type or a String that does not complete abruptlyand 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 ArithmeticExceptionthough 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.
好问题。我想这是一种投掷方式,ArithmeticException尽管这几乎不是一个合理的理由。以这种方式指定 Java 的一个更可能的原因是为了避免 JLS 和编译器中不必要的复杂性,以处理很少会咬人的边缘情况。
But this is all by the by. The fact is that 1/0is 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 代码,任何 Java 编译器都不应该将其标记为编译错误。(Java 编译器发出警告是合理的,前提是有一个编译器开关可以将其关闭。)
回答by polygenelubricants
I did some digging into the Bug Database, and discovered some interesting information.
我对 Bug 数据库进行了一些挖掘,并发现了一些有趣的信息。
Bug ID 4178182: JLS doesnt specify behavior for 1/0 as a constant expression
错误号 4178182:JLS 未将 1/0 的行为指定为常量表达式
The following code is illegal:
class X { static final int i = 1 / 0; }The value of this compile-time constant is undefined, therefore this has to be a compile-time error.Guy Steele confirmed about 18 months ago that this was indeed the intended behaviour.
A compile-time constant has to have its value available statically (that's what makes it a compile-time constant ;-) For example, the value of other constants whose values are determined by a constant that contains a division by zero are undefined. This affects the semantics of
switchstatements, definite assigment and unassignment, etc.
以下代码是非法的:
class X { static final int i = 1 / 0; }此编译时常量的值未定义,因此这必须是编译时错误。大约 18 个月前,Guy Steele 证实这确实是预期的行为。
编译时常量必须使其值静态可用(这就是使其成为编译时常量的原因;-)例如,其他常量的值由包含除以零的常量确定的常量是未定义的。这会影响
switch语句的语义、确定赋值和未赋值等。
Bug ID 4089107: javac treats integer division by (constant) zero as an error
错误号 4089107:javac 将整数除以(常量)零视为错误
public class zero { public static void main(String[] args) { System.out.println(1/0); } }Running the above yields:
zero.java:3: Arithmetic exception. System.out.println(1/0); ^ 1 error
public class zero { public static void main(String[] args) { System.out.println(1/0); } }运行上述收益率:
zero.java:3: Arithmetic exception. System.out.println(1/0); ^ 1 error
Bug ID 4154563: javac accepts division by zero constant expressions in case expressions.
错误号 4154563:javac 接受在 case 表达式中除以零常量表达式。
Java compiler crashes while trying to compile next test. This test also crashes all 1.2beta4 compiler versions, but bug is absent in 12.beta3. An example and compiler diagnostics follow:
public class B { public static void main(String argv[]) { switch(0){ case 0/0: } } }Evaluation: The compiler used to report all attempts to divide by the constant zero as compile-time errors. This was fixedin beta3 so that code would be generated for division by constant zero. Unfortunately this bug was introduced. The compiler should handle a division by zero in a case expression gracefully.
Java 编译器在尝试编译下一个测试时崩溃。此测试还会导致所有 1.2beta4 编译器版本崩溃,但 12.beta3 中不存在错误。示例和编译器诊断如下:
public class B { public static void main(String argv[]) { switch(0){ case 0/0: } } }评估:编译器用于将所有除以常数零的尝试报告为编译时错误。这在 beta3 中得到修复,以便生成代码以除以常数零。不幸的是,这个错误被引入了。编译器应该优雅地处理 case 表达式中被零除的情况。
Conclusion
结论
So the question of whether or not 1/0should 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.
所以是否1/0应该编译的问题是一个有争议的讨论话题,有些人引用 Guy Steele 的话说这应该是一个编译时错误,而其他人则说它不应该。似乎最终决定它既不是编译时错误也不是编译时常量。
回答by Marcelo Cantos
Java explicitly requiresinteger division by zero to trigger an ArithmeticException. The assignment to jcan't be elided because that would violate the spec.
Java明确要求整数除以零来触发ArithmeticException. j不能省略对的分配,因为这会违反规范。
回答by Corey
Well, if you look into the Double class, you will see the following:
好吧,如果您查看 Double 类,您将看到以下内容:
/**
* A constant holding the positive infinity of type
* <code>double</code>. It is equal to the value returned by
* <code>Double.longBitsToDouble(0x7ff0000000000000L)</code>.
*/
public static final double POSITIVE_INFINITY = 1.0 / 0.0;
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.
在 Float 类中进行了相同的计算,除了使用浮点数而不是双精度数。基本上,1/0 返回一个非常非常大的数字,大于 Double.MAX_VALUE。
This following code:
以下代码:
public static void main(String[] args) {
System.out.println(Double.POSITIVE_INFINITY);
System.out.println(Double.POSITIVE_INFINITY > Double.MAX_VALUE);
}
Outputs:
输出:
Infinity
true
Note the special case in printing out Double.POSITIVE_INFINITY. It prints out a string, though it's regarded as a double.
注意打印输出的特殊情况Double.POSITIVE_INFINITY。它打印出一个字符串,尽管它被视为双精度。
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).
要回答这个问题,是的,它在 Java 中是合法的,但是 1/0 解析为“无穷大”,并且与标准双精度(或浮点数,等等)的处理方式不同。
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.
我应该指出,我对它是如何或为什么以这种方式实施的一无所知。当我看到上面的输出时,对我来说这一切都像是黑魔法。
回答by TacB0sS
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/Ythe 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.
原因...良好的编程必须允许灵活性,因此您键入的所有表达式和每个代码都是编译器的变量,因此在数学表达式 X/ Y 中,编译器不关心 Y 变量值是否为 ( Y== 0) 或编译器的任何其他数字,这是一个变量......如果编译器还必须查看值,那将被视为运行时,不是吗。
回答by Daniel
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.
例如,如果您从一个文本文件中加载和解析“0”,然后试图除以它,Java 将不知道您在编译时在做什么,因为它不知道该外部文件的内容。
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.
此外,如果您要将任何变量设置为 0 并除以该变量,Java 将必须跟踪脚本中每个点的每个变量的每个可能值,以便在编译时捕获除以 0。
Might as well keep things consistent and make it a runtime-only exception.
不妨保持一致并使其成为仅限运行时的异常。
回答by charlie
Since others already answered the legality of 1/0, let's move to the second question:
既然其他人已经回答了 的合法性1/0,那么我们进入第二个问题:
- If this is legal, is there a good reason for it?
- What good could this possibly serve?
- 如果这是合法的,是否有充分的理由?
- 这有什么好处呢?
An answer could be:
答案可能是:
To tease a colleague of yours.;o)
When the colleague leaves the room with his computer left unlocked, sneak by and burry
1/0somewhere deep into a static initializerof some class that is used early in the application. This way he will find out soon enough after (or even during) the deployment of the application by encountering the unusualArithmeticExceptionand he will probably scratch his head for a while. Using this fail-fast way you can ensure it's a relatively harmless joke.
取笑你的同事。;o)
当同事离开房间时,他的电脑没有上锁,偷偷摸摸地潜入
1/0某个在应用程序早期使用的某个类的静态初始化器的深处。通过这种方式,他将在应用程序部署之后(甚至在部署期间)通过遇到异常情况很快发现,ArithmeticException并且他可能会挠头一段时间。使用这种快速失败的方式可以确保它是一个相对无害的笑话。
P.S.: It worked. ;o)
PS:它起作用了。;o)
回答by Will Hartung
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:
“智能”编译器可能会编译:
a = 1 + 2
as
作为
a = 3
But there's nothing that says the compiler HAS to do that. Other than that, 1/0 is a legal expression just like:
但是没有什么说编译器必须这样做。除此之外, 1/0 是一个合法的表达式,就像:
int a;
int b;
a = a/b;
is a legal expression.
是一个合法的表达。
At RUNTIME it throws an exception, but that's a runtime error for a reason.
在 RUNTIME 它抛出异常,但这是一个运行时错误是有原因的。

