Why can't overriding methods throw exceptions broader than the overridden method?

Java

Java Problem Overview


I was going through SCJP 6 book by Kathe sierra and came across this explanations of throwing exceptions in overridden method. I quite didn't get it. Can any one explain it to me ?

> The overriding method must NOT throw checked exceptions that are new or broader than those declared by the overridden method. For example, a method that declares a FileNotFoundException cannot be overridden by a method that declares a SQLException, Exception, or any other non-runtime exception unless it's a subclass of FileNotFoundException.

Java Solutions


Solution 1 - Java

It means that if a method declares to throw a given exception, the overriding method in a subclass can only declare to throw that exception or its subclass. For example:

class A {
   public void foo() throws IOException {..}
}

class B extends A {
   @Override
   public void foo() throws SocketException {..} // allowed

   @Override
   public void foo() throws SQLException {..} // NOT allowed
}

SocketException extends IOException, but SQLException does not.

This is because of polymorphism:

A a = new B();
try {
    a.foo();
} catch (IOException ex) {
    // forced to catch this by the compiler
}

If B had decided to throw SQLException, then the compiler could not force you to catch it, because you are referring to the instance of B by its superclass - A. On the other hand, any subclass of IOException will be handled by clauses (catch or throws) that handle IOException

The rule that you need to be able to refer to objects by their superclass is the Liskov Substitution Principle.

Since unchecked exceptions can be thrown anywhere then they are not subject to this rule. You can add an unchecked exception to the throws clause as a form of documentation if you want, but the compiler doesn't enforce anything about it.

Solution 2 - Java

The overriding method CAN throw any unchecked (runtime) exception, regardless of whether the overridden method declares the exception

Example:

class Super {
    public void test() {
        System.out.println("Super.test()");
    }
}

class Sub extends Super {
    @Override
    public void test() throws IndexOutOfBoundsException {
        // Method can throw any Unchecked Exception
        System.out.println("Sub.test()");
    }
}

class Sub2 extends Sub {
    @Override
    public void test() throws ArrayIndexOutOfBoundsException {
        // Any Unchecked Exception
        System.out.println("Sub2.test()");
    }
}

class Sub3 extends Sub2 {
    @Override
    public void test() {
        // Any Unchecked Exception or no exception
        System.out.println("Sub3.test()");
    }
}

class Sub4 extends Sub2 {
    @Override
    public void test() throws AssertionError {
        // Unchecked Exception IS-A RuntimeException or IS-A Error
        System.out.println("Sub4.test()");
    }
}

Solution 3 - Java

In my opinion, it is a fail in the Java syntax design. Polymorphism shouldn't limit the usage of exception handling. In fact, other computer languages don't do it (C#).

Moreover, a method is overriden in a more specialiced subclass so that it is more complex and, for this reason, more probable to throwing new exceptions.

Solution 4 - Java

I provide this answer here to the old question since no answers tell the fact that the overriding method can throw nothing here's again what the overriding method can throw:

  1. throw the same exception

    public static class A { public void m1() throws IOException { System.out.println("A m1"); }

    }

    public static class B extends A { @Override public void m1() throws IOException { System.out.println("B m1"); } }

  2. throw subclass of the overriden method's thrown exception

    public static class A { public void m2() throws Exception { System.out.println("A m2"); }

    }

    public static class B extends A { @Override public void m2() throws IOException { System.out.println("B m2"); } }

3) throw nothing.

public static class A 
{	
	public void m3()
	   throws IOException
	{
		System.out.println("A m3");
	}
}

public static class B 
    extends A
{	
	@Override
	public void m3()
	    //throws NOTHING
	{
		System.out.println("B m3");
	}
}

4) Having RuntimeExceptions in throws is not required.

There can be RuntimeExceptions in throws or not, compiler won't complain about it. RuntimeExceptions are not checked exceptions. Only checked exceptions are required to appear in throws if not catched.

Solution 5 - Java

To illustrate this, consider:

public interface FileOperation {
  void perform(File file) throws FileNotFoundException;
}

public class OpenOnly implements FileOperation {
  void perform(File file) throws FileNotFoundException {
    FileReader r = new FileReader(file);
  }
}

Suppose you then write:

public class OpenClose implements FileOperation {
  void perform(File file) throws FileNotFoundException {
    FileReader r = new FileReader(file);
    r.close();
  }
}

This will give you a compilation error, because r.close() throws an IOException, which is broader than FileNotFoundException.

To fix this, if you write:

public class OpenClose implements FileOperation {
  void perform(File file) throws IOException {
    FileReader r = new FileReader(file);
    r.close();
  }
}

You will get a different compilation error, because you are implementing the perform(...) operation, but throwing an exception not included in the interface's definition of the method.

Why is this important? Well a consumer of the interface may have:

FileOperation op = ...;
try {
  op.perform(file);
}
catch (FileNotFoundException x) {
  log(...);
}

If the IOException were allowed to be thrown, the client's code is nolonger correct.

Note that you can avoid this sort of issue if you use unchecked exceptions. (I am not suggesting you do or don't, that is a philosophical issue)

Solution 6 - Java

Let us take an interview Question. There is a method that throws NullPointerException in the superclass. Can we override it with a method that throws RuntimeException?

To answer this question, let us know what is an Unchecked and Checked exception.

  1. Checked exceptions must be explicitly caught or propagated as described in Basic try-catch-finally Exception Handling. Unchecked exceptions do not have this requirement. They don't have to be caught or declared thrown.

  2. Checked exceptions in Java extend the java.lang.Exception class. Unchecked exceptions extend the java.lang.RuntimeException.

public class NullPointerException extends RuntimeException

Unchecked exceptions extend the java.lang.RuntimeException. Thst's why NullPointerException is an Uncheked exception.

Let's take an example: Example 1 :

    public class Parent {
       public void name()  throws NullPointerException {
    	   System.out.println(" this is parent");
       }
}

public class Child  extends Parent{
     public  void name() throws RuntimeException{
    	     System.out.println(" child ");
     }
     
     public static void main(String[] args) {
		Parent parent  = new Child();
		parent.name();// output => child
	}
}

The program will compile successfully. Example 2:

    public class Parent {
       public void name()  throws RuntimeException {
    	   System.out.println(" this is parent");
       }
}

public class Child  extends Parent{
     public  void name() throws  NullPointerException {
    	     System.out.println(" child ");
     }
     
     public static void main(String[] args) {
		Parent parent  = new Child();
		parent.name();// output => child
	}
}

The program will also compile successfully. Therefore it is evident, that nothing happens in case of Unchecked exceptions. Now, let's take a look what happens in case of Checked exceptions. Example 3: When base class and child class both throws a checked exception

    public class Parent {
       public void name()  throws IOException {
    	   System.out.println(" this is parent");
       }
}
public class Child  extends Parent{
     public  void name() throws IOException{
    	     System.out.println(" child ");
     }
     
     public static void main(String[] args) {
		Parent parent  = new Child();
		
		try {
			parent.name();// output=> child
		}catch( Exception e) {
			System.out.println(e);
		}
	
	}
}

The program will compile successfully. Example 4: When child class method is throwing border checked exception compared to the same method of base class.

import java.io.IOException;

public class Parent {
       public void name()  throws IOException {
    	   System.out.println(" this is parent");
       }
}
public class Child  extends Parent{
     public  void name() throws Exception{ // broader exception
    	     System.out.println(" child ");
     }
     
     public static void main(String[] args) {
		Parent parent  = new Child();
		
		try {
			parent.name();//output=> Compilation failure
		}catch( Exception e) {
			System.out.println(e);
		}
	
	}
}

The program will fail to compile. So, we have to be careful when we are using Checked exceptions.

Solution 7 - Java

say you have super class A with method M1 throwin E1 and class B deriving from A with method M2 overriding M1. M2 can not throw anything DIFFERENT or LESS SPECIALIZED than E1.

Because of polymorphism, the client using class A should be able to treat B as if it were A. Inharitance ===> Is-a (B is-a A). What if this code dealing with class A was handling exception E1, as M1 declares it throws this checked exception, but then different type of exception was thrown? If M1 was throwing IOException M2 could well throw FileNotFoundException, as it is-a IOException. Clients of A could handle this without a problem. If the exception thrown was wider, clients of A would not have a chance of knowing about this and therefore would not have a chance to catch it.

Solution 8 - Java

Well java.lang.Exception extends java.lang.Throwable. java.io.FileNotFoundException extends java.lang.Exception. So if a method throws java.io.FileNotFoundException then in the override method you cannot throw anything higher up the hierarchy than FileNotFoundException e.g. you can't throw java.lang.Exception. You could throw a subclass of FileNotFoundException though. However you would be forced to handle the FileNotFoundException in the overriden method. Knock up some code and give it a try!

The rules are there so you don't lose the original throws declaration by widening the specificity, as the polymorphism means you can invoke the overriden method on the superclass.

Solution 9 - Java

The overriding method must NOT throw checked exceptions that are new or broader than those declared by the overridden method.

Example:

class Super {
    public void throwCheckedExceptionMethod() throws IOException {
        FileReader r = new FileReader(new File("aFile.txt"));
        r.close();
    }
}

class Sub extends Super {    
    @Override
    public void throwCheckedExceptionMethod() throws FileNotFoundException {
        // FileNotFoundException extends IOException
        FileReader r = new FileReader(new File("afile.txt"));
        try {
            // close() method throws IOException (that is unhandled)
            r.close();
        } catch (IOException e) {
        }
    }
}

class Sub2 extends Sub {
    @Override
    public void throwCheckedExceptionMethod() {
        // Overriding method can throw no exception
    }
}

Solution 10 - Java

What explanation do we attribute to the below

class BaseClass {

    public  void print() {
        System.out.println("In Parent Class , Print Method");
    }

    public static void display() {
        System.out.println("In Parent Class, Display Method");
    }

}


class DerivedClass extends BaseClass {

    public  void print() throws Exception {
        System.out.println("In Derived Class, Print Method");
    }

    public static void display() {
        System.out.println("In Derived Class, Display Method");
    }
}

Class DerivedClass.java throws a compile time exception when the print method throws a Exception , print () method of baseclass does not throw any exception

I am able to attribute this to the fact that Exception is narrower than RuntimeException , it can be either No Exception (Runtime error ), RuntimeException and their child exceptions

Solution 11 - Java

The overriding method must NOT throw checked exceptions that are new or broader than those declared by the overridden method.

This simply means when you override an existing method, the exception that this overloaded method throws should be either the same exception which the original method throws or any of its subclasses.

Note that checking whether all checked exceptions are handled is done at compile time and not at runtime. So at compile time itself, the Java compiler checks the type of exception the overridden method is throwing. Since which overridden method will be executed can be decided only at runtime, we cannot know what kind of Exception we have to catch.


Example

Let's say we have class A and its subclass B. A has method m1 and class B has overridden this method (lets call it m2 to avoid confusion..). Now let's say m1 throws E1, and m2 throws E2, which is E1's superclass. Now we write the following piece of code:

A myAObj = new B();
myAObj.m1();

Note that m1 is nothing but a call to m2 (again, method signatures are same in overloaded methods so do not get confuse with m1 and m2.. they are just to differentiate in this example... they both have same signature). But at compile time, all java compiler does is goes to the reference type (Class A in this case) checks the method if it is present and expects the programmer to handle it. So obviously, you will throw or catch E1. Now, at runtime, if the overloaded method throws E2, which is E1's superclass, then ... well, it's very wrong (for the same reason we cannot say B myBObj = new A()). Hence, Java does not allow it. Unchecked exceptions thrown by the overloaded method must be same, subclasses, or non-existent.

Solution 12 - Java

To understand this let's consider an example where we have a class Mammal which defines readAndGet method which is reading some file, doing some operation on it and returning an instance of class Mammal.

class Mammal {
    public Mammal readAndGet() throws IOException {//read file and return Mammal`s object}
}

Class Human extends class Mammal and overrides readAndGet method to return the instance of Human instead of the instance of Mammal.

class Human extends Mammal {
    @Override
    public Human readAndGet() throws FileNotFoundException {//read file and return Human object}
}

To call readAndGet we will need to handle IOException because its a checked exception and mammal's readAndMethod is throwing it.

Mammal mammal = new Human();
try {
    Mammal obj = mammal.readAndGet();
} catch (IOException ex) {..}

And we know that for compiler mammal.readAndGet() is getting called from the object of class Mammal but at, runtime JVM will resolve mammal.readAndGet() method call to a call from class Human because mammal is holding new Human().

Method readAndMethod from Mammal is throwing IOException and because it is a checked exception compiler will force us to catch it whenever we call readAndGet on mammal

Now suppose readAndGet in Human is throwing any other checked exception e.g. Exception and we know readAndGet will get called from the instance of Human because mammal is holding new Human().

Because for compiler the method is getting called from Mammal, so the compiler will force us to handle only IOException but at runtime we know method will be throwing Exception exception which is not getting handled and our code will break if the method throws the exception.

That's why it is prevented at the compiler level itself and we are not allowed to throw any new or broader checked exception because it will not be handled by JVM at the end.

There are other rules as well which we need to follow while overriding the methods and you can read more on Why We Should Follow Method Overriding Rules to know the reasons.

Solution 13 - Java

The subclass's overriding method can only throw multiple checked exceptions that are subclasses of the superclass's method's checked exception, but cannot throw multiple checked exceptions that are unrelated to the superclass's method's checked exception

Solution 14 - Java

Java is giving you the choice to restrict exceptions in the parent class, because it's assuming the client will restrict what is caught. IMHO you should essentially never use this "feature", because your clients may need flexibility down the road.

Java is an old language that is poorly designed. Modern languages don't have such restrictions. The easiest way around this flaw is make your base class throw Exception always. Clients can throw more specific Exceptions but make your base classes really broad.

Solution 15 - Java

Rule of handling check and unchecked exceptions on overridden methods

-When parent-class method declares no exception, then child-class overriding- method can declare,

 1. No exception or
 2. Any number of unchecked exception
 3. but strictly no checked exception

-When parent-class method declares unchecked exception, then child-class overriding-method can declare,

 1. No exception or
 2. Any number of unchecked exception 
 3. but strictly no checked exception

-When parent-class method declares checked exception, then child-class overriding-method can declare,

 1. No exception or
 2. Same checked exception or
 3. Sub-type of checked exception or
 4. any number of unchecked exception

All above conclusion hold true, even if combination of both checked & unchecked exception is declared in parent-class’ method

Ref

Solution 16 - Java

Overriding method can (yet, it does not have to) throw:

  1. any unchecked,

    and

  2. only those checked exceptions that are covariant types (same or extender) of whatever overridden method throws.

Solution 17 - Java

Consider following three statements

  1. Overloaded method must change the argument list I. Overloaded method may change the return type I. Overloaded method may declare broader checked exception Choose all that are true.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionarpanoidView Question on Stackoverflow
Solution 1 - JavaBozhoView Answer on Stackoverflow
Solution 2 - Javasyrus.phoenixView Answer on Stackoverflow
Solution 3 - JavacaligariView Answer on Stackoverflow
Solution 4 - JavaDeveloper Marius ŽilėnasView Answer on Stackoverflow
Solution 5 - JavaDilum RanatungaView Answer on Stackoverflow
Solution 6 - JavaSoudipta DuttaView Answer on Stackoverflow
Solution 7 - JavaPeter PerháčView Answer on Stackoverflow
Solution 8 - JavaplanetjonesView Answer on Stackoverflow
Solution 9 - Javasyrus.phoenixView Answer on Stackoverflow
Solution 10 - JavaabhiView Answer on Stackoverflow
Solution 11 - JavaAniket ThakurView Answer on Stackoverflow
Solution 12 - JavaNaresh JoshiView Answer on Stackoverflow
Solution 13 - JavaFegoView Answer on Stackoverflow
Solution 14 - JavaJonathanView Answer on Stackoverflow
Solution 15 - JavaRamesh PapagantiView Answer on Stackoverflow
Solution 16 - JavaGiorgi TsiklauriView Answer on Stackoverflow
Solution 17 - Javaprathamesh hukkeriView Answer on Stackoverflow