Search code examples
javadivide-by-zero

Is 1/0 a legal Java expression?


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?

Solution

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