Is 1/0 a legal Java expression?

不打扰是莪最后的温柔 提交于 2019-12-17 05:00:51

问题


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?

回答1:


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.)




回答2:


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

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 switch statements, definite assigment and unassignment, etc.

Bug ID 4089107: javac treats integer division by (constant) zero as an error

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

Bug ID 4154563: javac accepts division by zero constant expressions in case expressions.

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 fixed in 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.

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.




回答3:


Java explicitly requires integer division by zero to trigger an ArithmeticException. The assignment to j can't be elided because that would violate the spec.




回答4:


Well, if you look into the Double class, you will see the following:

/**
 * 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.

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.

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.




回答5:


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:

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.




回答6:


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.




回答7:


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.




回答8:


Since others already answered the legality of 1/0, let's move to the second question:

  • 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/0 somewhere deep into a static initializer of 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 unusual ArithmeticException and he will probably scratch his head for a while. Using this fail-fast way you can ensure it's a relatively harmless joke.

P.S.: It worked. ;o)



来源:https://stackoverflow.com/questions/2934063/is-1-0-a-legal-java-expression

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!