Is 1/0 a legal Java expression?
Asked Answered
V

8

43

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?
Valorize answered 29/5, 2010 at 6:22 Comment(7)
Downvoter: care to explain how this question is unclear or not useful? Because I'll have many more questions in the future, so I'd like to know where to improve.Valorize
+1 Good question. Not even findbugs complains about division by zero (at compile time :-/).Instantly
@polygenelubricants: I honestly don't know if such details will make you a better programmer or not. 25+ years of programming here and besides from a "language lawyer" POV and a "Java Puzzlers" POV (altough the Java puzzlers are better than this), I think there's a non-zero probability that this is just hair-splitting and wasted time (just being honest here: most of the professional developers who answered here probably had no clue and it probably didn't harm them in any way in their carreer not knowing this Java detail). I, for one, don't want to see SO infested with questions like this :(Lyndell
Note that I didn't say it wasn't interesting: all I'm saying is that, to me, there's a high probability that it will not harm you in your (Java) programming career not knowing about such details and that hence I'm not sure such questions are really that helpful to help make people better programmer. Hence, to me, SO shouldn't get rid with "many more questions (like this) in the future".Lyndell
Another way to state it would be this: to me all the time spend nitpicking/answering/commenting on questions like this (which apparently you have many more like in the future) could be spend learning, say, a bit of Lisp... And that would really make you a better programmer.Lyndell
@Webinator Another viewpoint, from another multi-decade programmer. Long ago, someone I respected very much told me that if I didn't know at least three ways to break a tool, I hadn't really learned to use it. When I got into programming, I extended that metaphor to apply to edge conditions, odd behaviors, and even some nitpicking. Programming is all about managing details.Fremont
@Webinator: I'm more of a computer scientist than a software engineer, so language issues like this deeply interest me. I'm not only concerned with how to write better programs. I'm also concerned with how to design better languages.Valorize
A
34

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

Abuttals answered 29/5, 2010 at 6:28 Comment(5)
It reasonable to not have a warning, as dividing by a compile time constant which evaluates to zero isn't a common enough cause of errors to waste development time detecting.Helmer
@Pete - I can accept that, though there are precedents for this kind of warning. For example the Eclipse Java compiler will emit a warning if it figures out that a statement will always throw an NPE.Abuttals
Considering the number of times I've hit a NPE vs an ArithmeticException, that's quite reasonable.Helmer
@Pete: The compiler has to check anyway whether the expression throws an Exception, since in this case it is not to be considered a compile-time constant. So giving a warning in this case would not be so very much overhead.Yurikoyursa
The bytecode does not contain a switch statement, so it needs to be evaluated at compile time. One divided by zero cannot be calculated, and so you get a compilation error (the compiler is essentially running it to evaluate it).Renfro
V
20

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.

Valorize answered 29/5, 2010 at 13:28 Comment(0)
I
3

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.

Intransitive answered 29/5, 2010 at 10:18 Comment(3)
Floating point types (double and float) work differently from integers. The FP types have a way to represent infinity, which the integer types do not have. The original question was about integers, so a discussion about FP types is not really relevant.Wendelin
The question is asking if division by zero "should compile anytime anywhere?". The examples provided do use integers, but it is never explicitly asked if integers in particular can hold a value divided by zero, only if it's legal in the language. The answer is to that, then, is yes.Intransitive
The question explicitly asks about the expression 1/0, not the expression 1.0/0.0, so I still agree with Jesper's comment. Imo, it was quite obvious that this was a discussion whether if, and if so why, 1/0 should be a compile time error as opposed to a runtime exception, neither of which is appropriate for floating point types.Atlantis
N
2

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.

Nananne answered 29/5, 2010 at 6:30 Comment(1)
If it compiles, certainly it can't be elided; this much is known and is acknowledged. The question is whether it should even compile in the first place.Valorize
A
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:

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.

Alric answered 29/5, 2010 at 6:27 Comment(6)
int a; int b; a = a/b; throws a compile time exception by javac.Tingey
@Bart K. - there's no such thing as an "exception that is thrown at compile time". The compiler will indeed give you an error. Exceptions are only thrown at runtime.Wendelin
sigh The expression is legal, the compiler error is due to the uninitialized variables. Surprised I wasn't voted down for missing the semi-colon on the first expression.Alric
@Will, I didn't say anything about the expression being (il)legal. You said "At RUNTIME it throws an exception" which is not true: int a; int b; a = a/b; won't reach runtime.Tingey
@Bart but you are being pedantic expecting code written simply to promote the narrative is supposed to be legal and perfect code. The intent of the code is clear, even if it is imperfect Java because the a and b aren't initialized. I typed them to ensure someone wouldn't chime it "what if b is a String" or some other nonsense.Alric
@Will, no, I'm not being pedantic (at least, it is not my intention). Since you specifically said it would throw a runtime exception, I merely pointed out that this is not true. And obviously your intent was not clear (to me) since I thought that you meant that the "not initialized" error would be thrown at runtime, which was, looking at your comments, not your intent.Tingey
V
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.

Villiform answered 29/5, 2010 at 6:39 Comment(4)
I don't think that checking for division by zero would increase compile time considerably.Instantly
It would if the "zero" was a variable. Then Java would have to perform every calculation involving that variable preceding the division statement to determine whether or not it is zero at that point, and in many instances this is impossible (e.g. variable loaded from external source). If it WASN'T a variable, it'd mean you actually coded: a = b/0; and that would be a pretty amateurish mistake one could surely only make while under the influence :PAutoionization
never said it would increase compiling time. what I was trying to say was that the compiler does not evaluate the expression on compilation, but it does determine the type of the variable (int/float/...) in the division and its value and saves the type and value in the class file as byte code, and it does not evaluate the expression. Because it would be endless and pointless to evaluate all the expressions possible.Villiform
@OliverWeiler - the (compile time) performance cost is irrelevant. The relevant point is whether the compiler is allowed to implement that check and call it a compilation error. A compiler is not allowed to do smart things like that unless the language specification permits it. In this case, the JLS doesn't permit this. (Smart compilers that do helpful things that the JLS doesn't sanction are a bad thing because they lead to source code portability problems.)Abuttals
A
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.

Autoionization answered 29/5, 2010 at 6:42 Comment(2)
Why bother catching String s = (String) Integer.valueOf(0); // doesn't compile! at compile-time if it's going to throw ClassCastException at run-time anyway?Valorize
Because Integer.valueOf(0) is a type issue (integer argument when it was expecting a string) and type issues are detected at compile-time thanks to Java's strict typing. Division by zero is a calculation issue, and Java does not perform calculations at compile-time because in many situations it's impossible (e.g. calculations on a variable loaded from a DB/external file). Therefore all calculation issues are caught at run-time.Autoionization
S
0

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)

Sudoriferous answered 8/1, 2016 at 9:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.