Why can't I handle Exception e with try / catch clause?

7.4k views Asked by At

When I compile the following code everything goes fine and output is as expected:

class Propogate {
    public static void main(String[] args) {
        Propogate obj = new Propogate();
        try {
            obj.reverse("");
        } catch (IllegalArgumentException e) {
            System.out.println(e);
        } finally {
            System.out.println("That's all folks");
        }
    }
    String reverse(String s) {
        if(s.length() == 00) {
            throw new IllegalArgumentException();
        }
        String reversed = "";
        for(int i=s.length() - 1; i >= 0; --i) {
            reversed += s.charAt(i);
        }
        return reversed;
    }
}

Program results:

java.lang.IllegalArgumentException
That's all folks

However, when I run the exact same code but change the exception type from

IllegalArgumentException to plain old exception all I get is:Propogate.java:14: error:    
unreported exception Exception; must be caught or declared to be thrown
                        throw new Exception();
                    ^
1 error

What is special about the parent type Exception() that I can't handle it with a try / catch statement? Why does IllegalArgumentException() allow me to handle it with a try / catch statement just fine. These are the thoughts of a being kept awake at night with the terror of failing, nay, just taking the SCJP exam.

4

There are 4 answers

3
Louis Wasserman On BEST ANSWER

A method which throws an exception that is not a subclass of RuntimeException must declare that it throws that Exception. You must write

String reverse(String s) throws Exception {

if you're going to throw an Exception with it. Once you do that, you can catch it with a try/catch normally.

2
musical_coder On

IllegalArgumentExceptions are unchecked exceptions, because they are subclasses of RuntimeException. So the compiler isn't going to check them. Non-RuntimeException objects, such as Exception, are checked by the compiler, which explains what you're seeing.

Because you're catching the exception in main(), which is the bottom of your call stack, I think it's better to cover all contingencies by having catch (Exception e) instead.

0
zbwang On

A method which throws an exception that is a subclass of RuntimeException dosn't have to declare that it throws that Exception just following the method. That's why the first code goes well.

However,when you change the exception type to Non-RuntimeException, you have to make the method throw the Exception, or the compile error will occur. That's why the second code goes wrong.

0
Stephen C On

The other answers have covered why the compiler is unhappy, and what you can do about it. But I think that your real mistake is throwing Exception in the first place.

Throwing Exception is almost always a bad idea. The reason is that if your code throws Exception, it (or someone else's code) then typically has to catch the exception. But the problem with catching Exception is that your code also catches any / all subtypes of Exception that might be thrown by your code. That includes unchecked exceptions that might be caused by bugs in your code, etcetera.

For example:

public class Test {
    private static Integer a;
    private static Integer b;

    public static void main(String[] args) {
        try {
            if (a.equals(b)) {
                throw Exception("they are the same");
            } 
            System.out.println("they are different");
        } catch (Exception ex) {
            System.out.println(ex.message());
        }
    }
}

When you run this, you will get the mysterious output "null". (Exercise for reader ... figure out precisely why.)

Declaring a method as throws Exception is even worse, because now the caller is forced to either catch Exception (bad) or propagate it (worse). Methods that are declared as throws Exception are like a cancer.

Declaring the main method as throws Exception is a special case. The main method is (usually) called by JVM infrastructure that is designed to cope with any exception. It just prints a stacktrace to standard error. Even so, it is probably neater to handle the exceptions yourself. In a "production grade" codebase, you would typically want to log the unexpected exception in the error logs.