In Java, overriding allows a subclass to provide a specific implementation of a method already defined in its superclass. However, when exceptions are involved, Java enforces specific rules to ensure that exception handling remains consistent and safe across inheritance hierarchies.
Rules for Exceptions in Overriding Methods
Rule | Description |
---|---|
Allowed | The overriding method can throw fewer or more specific (subclass) checked exceptions. |
Not Allowed | The overriding method cannot throw new or broader checked exceptions than the overridden method. |
Unchecked Exceptions | There are no restrictions on throwing unchecked (runtime) exceptions in the overriding method. |
Simple Program Example: Software Engineer Hierarchy
This example demonstrates how exceptions behave during method overriding using a Software Engineer designation scenario.
// Base class class SoftwareEngineer { public void doWork() throws java.io.IOException { System.out.println("Software Engineer is coding..."); throw new java.io.IOException("Build failed."); } } // Subclass overriding with a more specific exception class SeniorEngineer extends SoftwareEngineer { @Override public void doWork() throws java.io.FileNotFoundException { System.out.println("Senior Engineer is reviewing code..."); throw new java.io.FileNotFoundException("Review file missing."); } } // Subclass overriding without throwing any exception class Intern extends SoftwareEngineer { @Override public void doWork() { System.out.println("Intern is learning..."); // No exception thrown } } // Subclass overriding with unchecked exception class TechLead extends SoftwareEngineer { @Override public void doWork() throws RuntimeException { System.out.println("Tech Lead is managing tasks..."); throw new RuntimeException("Task mismanagement error."); } } // Illegal override (Uncommenting this will cause compile-time error) /* class Architect extends SoftwareEngineer { @Override public void doWork() throws Exception { // ❌ Compile-time error System.out.println("Architect is designing..."); } } */ public class EngineerDemo { public static void main(String[] args) { SoftwareEngineer engineer; // Senior Engineer engineer = new SeniorEngineer(); try { engineer.doWork(); } catch (java.io.IOException e) { System.out.println("Caught: " + e.getMessage()); } // Intern engineer = new Intern(); try { engineer.doWork(); } catch (java.io.IOException e) { System.out.println("Caught: " + e.getMessage()); } // Tech Lead engineer = new TechLead(); try { engineer.doWork(); } catch (RuntimeException e) { System.out.println("Caught RuntimeException: " + e.getMessage()); } } } /* Senior Engineer is reviewing code... Caught: Review file missing. Intern is learning... Tech Lead is managing tasks... Caught RuntimeException: Task mismanagement error. */
When overriding methods, Java ensures that exception handling stays safe and predictable. Subclasses may:
-
Not declare broader checked exceptions
-
Declare narrower (subclass) checked exceptions
-
Declare or skip unchecked exceptions freely
This approach maintains robust polymorphism and API integrity in real-world applications like employee roles and responsibilities.