Override exception

As you know, in case the method overrides. If the method of the child class throws a specific exception, then the forced method of the parent class must throw the same checked exception or exception of the parent class, otherwise we get a compilation error. But there is no rule for an excluded exception.

But assuming Java allows the method of the parent class to check for an exception that is a child of the thrown exception of the class of the child class.

Can someone explain why this is not allowed in Java.


Let's ask the question differently:

you have class A -

class A { public void doStuff() throws SQLException { } } 

and class B continues to A -

 class B extends A { public void doStuff() throws Exception { } } 

It will throw an exception at compile time due to a method contract violation.

Suppose Java would allow this then, what would be the consequences?

+7
java
source share
6 answers

I suppose you are asking why I cannot do this:

 class Parent { void doStuff() throws FileNotFoundException { } } class Child extends Parent { @Override void doStuff() throws IOException { } } 

This is just what happens when I do:

 final Parent parent = new Child(); try { parent.doStuff(); } catch (FileNotFoundException e) { e.printStackTrace(); } 

And Child decides to throw a, say SocketException ?

I, correctly, try catch FileNotFoundException and catch FileNotFoundException from the parent.doStuff call, but this will not catch a SocketException .

As I have a thrown exception thrown. This is not allowed.

If I specifically try and catch SocketException , this will result in a compiler error, because a SocketException not declared as thrown from parent.doStuff .

The only way to solve this in the general case is to always catch Exception , since any child class can declare that it produces a more general type and bypasses my catch . This is obviously not perfect.

+8
source share

The throws is part of the method signature, and to override a method, an overriding method must have the same signature as the override method.

Therefore, if class B extends class A and A defines:

 public void foo (int param) throws SomeException { .... if (something) throw new SomeException (); .... } 

Then B can only redefine foo using the same signature:

 public void foo (int param) throws SomeException { super.foo(param); .... if (something) throw new SomeOtherException (); .... } 

SomeOtherException must be a subclass of SomeException , because it is the type of exception that the method signature allows you to sign. If the override method tries to throw an exception of the type that is the SomeException , this will violate the method's contract.

Let declare a hierarchy of classes of classes of exceptions:

 SuperException SomeException SomeOtherException AnotherSomeException 

What you offer ( Java allows parent class method to have checked exception which is child to the child class method checked exception ) will allow the overriding method in the child class to throw any SuperException exceptions that would allow it to throw AnotherSomeException . This violates the method signature because AnotherSomeException not a subclass of SomeException .

To expand on my comment, let's look at what happens if Java allows what you offer.

Suppose class C has a method bar , which takes an instance of class A and calls foo .

 public class C { .... public void bar (A a) { try { a.foo (); } catch (SomeException ex) { .... } } } 

Since foo SomeException throw SomeException , any code that calls foo must handle this exception or declare that it can throw this exception. Now, if Java allows B override foo , but changes its declaration to public void foo() throws Exception , the implementation of foo in B can throw any subclass of the Exception class. Since bar does not even know that B exists, it does not know that it should catch any exception other than SomeException and its subclasses. Therefore, the compiler cannot mark this code as an error, but if the calling bar object passes an instance of B , the code will become invalid only at runtime, since it can throw a checked exception that is neither caught nor declared by bar . Therefore, Java does not allow changing the throws when overriding a method.

+1
source share

The overriding method cannot throw a checked exception if it is not specified in the parent class. The reason is because you want to be able to use a subtype instance wherever you can pass a supertype, i.e. Your subtype should behave just like your supertype. However, if your subtype can throw an exception, then it does not behave the same: it can throw an exception. The same is true for excluded exceptions, but, as the name already tells us, they are not checked by the compiler, so it just does not display statically.

I suggest you take a look at the principle of the Liskov signature .

An example of why it would be bad if the subclass chose an exception, where the superclass promised to throw an exception:

 class Animal { void eatMeat() {System.out.println("eating meat");} } class Zebra extends Animal { void eatMeat() throws IsVegetarianException {throw new IsVegetarianException(); } } 

Well ... maybe your Zebra not an animal, or the Animal interface is too wide. Maybe not all Animal eat meat. By the way: this happened in various interfaces of Java interfaces. They solve this by throwing an unchecked NotSupportedException , but this is just a design flaw for which there is no good solution other than a design change.

+1
source share

I may be wrong, but I think you are asking why superclass A cannot extend subclass B, which extends class A.

This cannot exist because there is a lack of clarity over the parent class.

+1
source share

If you override a method without a throw declaration, you can throw a RuntimeException or subclass without a declaration.

 class A { public void run() { } } class B extends A { @Override public void run() { throw new RuntimeException("throw without declaration"); } } 

From javadoc :

RuntimeException , and its subclasses are thrown exceptions. Unchecked exceptions should not be declared in a method or the constructor throws a sentence if they can be thrown by executing a method or constructor and propagated outside the method or constructor boundary.

0
source share

Because throws SQLException really means "throw only SQLException " or in other words do not throw anything except SQLException

So, if you throw away something else, you break this contract. On the other hand, you can do it differently.

 class A { public void doStuff() throws Exception { } } class B extends A { public void doStuff() throws SQLException { } } 

because you just do a more rigorous contract this way.

0
source share

All Articles