简体   繁体   中英

Handling exceptions in a hierarchy of overridden methods in Java

Consider a Java class hierarchy such as:

abstract class Exp { public void generate(); }
class EffExp extends Exp {...}
clas PureExp extends Exp {...}
class NewExp extends EffExp {...}
etc, etc.

The implementation of generate inside NewExp was changed to throw an IOException .

public void generate() throws IOException {...}

The other implementations of generate don't do any IO hence don't need to throw it. The compiler complains and forces me to declare all methods in the class hierarchy to throw the exception. Is this really the only way forward? It seems rather intrusive.

I could of course catch the exception where it happens, inside NewExp , but that doesn't really make sense. The exception should propagate to the top and stop the program execution.

The more general question here is: if you have a hierarchy of methods that override each other, do they all have to be declared to throw the same set of exceptions?

Just remember One Rule : -

  • You cannot add more restriction to the method you override. The restrictions can be for eg : - adding an new Checked Exception , decreasing the method visibility.

So, if you have to (no choice), make your overriding method throw a Checked Exception (Note that, you can add a unchecked Exception, though, but it wouldn't make any sense), just add the exception in the throws clause of the method you are overriding.

So, in simple words, the signature of your overridden method should match exactly with the one that overrides it.


Now the simple reasoning behind this is - Polymorphism .

In polymorphism, as you know that, you can have a super type reference point to a sub class object. So, you can have: -

SupClass ref = new SubClass();
ref.method1();

Now, while checking for the existence of method1 , compiler is only concerned about the reference type. So, it checks in SupClass , and allows the access accordingly.

Now, imagine what happens, when at runtime, when ref is actually pointing to SubClass object, JVM finds that method1 throws a new exception, that was not checked by the compiler . It will crash. That is why it is not allowed.

Suppose the scenario is something like :

abstract class Exp { public void generate(); }
class EffExp extends Exp { public void generate throw IOException(....)....}
clas PureExp extends Exp {public void generate(....)....}

We use abstract class notation so that we could implement our other classes without worrying about the actual implementation . If we make actual; implementation narrowed ie throw Exception in some case and don't throw in some other case then its clearly a violation of Java being Robust. So you need to be clearly in sync. for all the methods.

Although you can increase the visibility by throwing a Parent "Exception".

In abstract class you can define to throw java.lang.Exception

abstract class Exp { public abstract void generate() throws Exception; }

And in derived classes be more specific about what type of exception you throw.

Just consider this simple hypothetical code that, let's assume... fits your description:

Exp ex = new NewExp(); 
try {
ex.generate(); //It should throw an exception, but has no such method signature. 
} catch(AnException e) { //Nope, not allowed.
 ...
}

Does it need to throw a checked exception. Could you wrap it in a runtime exception?

public void generate() {
     try {
     ....
     } catch (IOException e ){
        RuntimeException re = new RuntimeException();
        re.initCause(e);
        throw re;
     }   
}

(not checked this for compilation but it should give you a general idea

If you are overriding a method, the overridden method in a superclass can only declare to throw that exception (checked) or its superclass. Otherwise you'll loose polymorphism and hence not allowed in Java

  1. We can not introduce a new checked exception in the overridden method but can have child checked exception or the same exception as handled in the parent class. Even if we do then if we refer to a child object with the parent reference it then compiler will force to catch the exception declared in the parent class method then look at the below example:

     class Parent{ public void method throws IOException{ } } class Child extends Parent{ public void method throws SQLException{ } } class Test{ public static void main(){ Parent p=new Child(); try{ p.method(); }catch(IOException e){ e.printStackTrace(); } } } 

    In the above program, child class method throws SQLException but Compiler will force to catch IOException. Because at compile time it is not known to the compiler as child object is being referred from a parent reference. But we can declare any unchecked exception as compiler will not enforce try/ctach or throws for them.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM