views:

291

answers:

7
+12  Q: 

try-catch problem

Hey guys, I am a java newbie, my question is about try-catch blocks on a simple division by zero example. You see the first line of try? If I cast any of those two variables to the double the program does not recognize the catch block. In my opinion, whether I cast or not only the catch block must be executed. What is wrong on this code? Thanks.

public static void main(String[] args) {

    int pay=8,payda=0;  

    try {

        double result=pay/(double)payda; // if I cast any of the two variables, program does not recognize the catch block, why is it so?
        System.out.println(result);
        System.out.println("inside-try");


    } catch (Exception e) {

        System.out.println("division by zero exception");
        System.out.println("inside-catch");

    }
}
+20  A: 

Divide by zero is valid for floating point numbers.

  • 1/0 yields Infinity.
  • (-1)/0 yields -Infinity.
  • 0/0 yields NaN.

These "numbers" are properly defined in IEEE 754.

Integer division by zero, on the other hand, throws because one cannot represent infinity as an int.

KennyTM
If floating point division cannot throw an exception, then the try / catch should be removed and error codes used instead.
Hamish Grubijan
I don't think `int` throws because it can't represent infinity. 1/0 is simply meaningless, and that's why it throws. Floating point, on the other hand, did some hand-waving and said "it should be infinity".
GMan
+3  A: 

The answer lies in your program's own output - it prints "Infinity" for result. This is because Java only disallows integer division by zero - floating point division by zero is legal and produces Infinity.

See the documentation of Double and Float for the POSITIVE_INFINITY and NEGATIVE_INFINITY constants.

danben
+9  A: 

I'd suggest verifying:

if (divisor != 0) {
    // calculate
}

rather than catching an exception

Bozho
+1  A: 

Because dividing two doubles returns a Infinity, but doesn't throw. You can use isInfinite() to check for this. However, the appropriate solution (as already noted) is to check the denominator before the division.

Matthew Flaschen
dividing only returns a NaN if one of the arguments is NaN or both are infinity or both are zero. Dividing a nonzero by zero - the question - results in positive or negative Infinity. http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.17.2
Carlos Heuberger
+2  A: 

Only division by zero with integers will raise an ArithmeticException. Division by zero with double or float will result in Infinity.

Desintegr
+5  A: 

Since you are a self-proclaimed "newbie", I think it would be a good idea to point out some broader issues with your code. (I know it is not production code, but just lets assume for the sake of argument that it was.)

  • If an exception is expected, it is usually simpler, clearer and more efficient if you detect the condition that will give rise to the exception. In this case, if you expect divisor to occasionally be zero it is better to test it before doing the division.

  • On the other hand, if an exception is totally unexpected (i.e. a "bug") the best strategy is to let the exception propagate to the outermost level. At that point your application catch should catch all exceptions, log the exception stacktrace and bail out.

  • Apart from the previous bullet, it is a bad idea to catch Exception, RuntimeException, Throwable or Error. Doing this will catch a large number of exceptions that you probably don't intend to catch. In this case, since you are expecting an ArithmeticException, you should catch just that.

  • It is rarely correct to use float or double in financial applications. These types are not exact, but financial applications typically require quantities of money to be handled exactly.

  • More generally, floating point numbers are inherently hard for lay people (and newbies) to understand. A lot of the "truths" that people expect to hold actually don't hold. For example, a floating point calculation of 1.0/3.0 + 1.0/3.0 + 1.0/3.0 does not give 1.0. Similarly (as you discovered) division by zero behaves differently. If you want to use floating point safely, you need to understand the pitfalls.

EDIT elaborating the first point in response to @Jay's comment.

First, I deliberately used the word "usually". There are cases where avoiding throwing the expected exception achieves nothing.

Having said that, you often don't want a generic "expected" exception to happen even if your application cannot deal with the situation immediately. For example, if the OP's code was part of something larger, it may be better to explicitly throw IllegalArgumentException (if this is a violation of an API contract) or some checked UserEnteredRubbishException if we know that this is a result of bad user input (and there is some opportunity to report / correct it).

The fact that we are "expecting" an exception means by definition that we know more about it than (say) a generic ArithmeticException would say. If we allow a generic exception to propagate, it makes it harder for a catch block many stack frames to act appropriately. In this case for example, the remote catch block could not diagnose the cause of the divide-by-zero with any certainty. The ArithmeticException might have come from a different part of the application, and might not even be a divide-by-zero! The way to address is to explicitly throwing a more specific exception.

Stephen C
I'd quibble with your first point. If a special case is expected AND there is something you can do to handle it and continue processing, then yes, you should check for it rather than throwing an exception. But if, no matter how expected a special case is, all you can do when it happens is cry panic and let loose the dogs of war, then just throw an exception.
Jay
But mega dittos on #3 and #4. Catching a generic exception is rarely productive. You have no idea what you're catching. By the way, I might add: Corollary: Don't throw generic exceptions. If your program detects an error condition and you want to throw an exception, take the ten minutes to create a new class for it that extends exception. Don't just 'throw new Exception("Foo was missing a bar")' or whatever.
Jay
+1  A: 

No one should try to expect RuntimeException to be thrown from their code. These Exceptions can be (and should be) avoided easily.

fastcodejava