What rule governs the checked exceptions an overriding method may declare in its throws clause?
answer
- Override: checked throws can only narrow or shrink, never broaden
- Same / subclass / fewer / none = OK
- New or superclass checked exception = compile error
- Unchecked exceptions are exempt
- It's Liskov substitution applied to throws
basics
~10 sAn overriding method cannot declare new or broader checked exceptions than the method it overrides. It may declare the same ones, narrower (subclass) ones, fewer, or none. Unchecked exceptions are unrestricted.
solid answer
~50 sThis is an application of the Liskov substitution principle to the throws clause. When a subclass overrides a method (or an implementation implements an interface method), its throws clause for checked exceptions must be no wider than the supertype's. Concretely, every checked exception the override declares must be the same as, or a subclass of, some checked exception declared by the overridden method. The override may declare fewer exceptions, or none at all, and may narrow to subtypes — but it may not introduce a brand-new checked exception or a broader superclass. The reason: callers compile against the supertype's contract, so any caller that handled the declared checked exceptions must remain correct when a subtype instance is substituted. Unchecked exceptions (RuntimeException, Error) are exempt — an override can throw any of them freely, since callers were never required to handle them in the first place.
go deeper
May not know this rule; that's acceptable at junior level.
Knows an override cannot add broader checked exceptions and can recognize the resulting compile error.
States the rule precisely (same/subclass/fewer/none), knows unchecked is exempt, and connects it to caller-handler safety.
Frames it as Liskov substitution applied to the throws clause and can discuss how the compiler enforces only the checked-exception slice of substitutability.
## The setup When class B overrides a method from class/interface A, the override must remain **substitutable**: code written against A's method must keep working when given a B. Java enforces a piece of this for **checked** exceptions in the `throws` clause. ## The rule An overriding method's `throws` clause **may not broaden** the set of checked exceptions. Each checked exception it declares must be: - the **same** checked exception declared by the overridden method, or - a **subclass** of a checked exception declared by the overridden method. The override is also free to: - declare **fewer** checked exceptions, - declare **none** at all, - declare **narrower** (subtype) exceptions. It **may not**: - declare a **new** checked exception not covered by the parent's list, - declare a **broader** (superclass) checked exception. ## Why A caller holding a reference of the supertype writes handlers based on the supertype's declared checked exceptions: ```java A a = getSomeImplementation(); // might actually be a B try { a.read(); // A.read() declares throws IOException } catch (IOException e) { ... } // caller handles exactly what A promised ``` The compiler only knows about `A.read()`'s contract. If `B.read()` could throw a *new* checked exception (say `SQLException`), the caller above would have an unhandled checked exception at runtime that the compiler never forced them to catch — breaking the catch-or-declare guarantee. Restricting overrides to a subset (or subtypes) keeps every supertype caller's existing handlers valid. ## Examples ```java class A { void read() throws IOException {} } class B extends A { @Override void read() throws FileNotFoundException {} // OK: subclass of IOException } class C extends A { @Override void read() {} // OK: declares none } class D extends A { @Override void read() throws Exception {} // COMPILE ERROR: broader } class E extends A { @Override void read() throws SQLException {} // COMPILE ERROR: new, unrelated checked } ``` ## The unchecked exemption The rule applies **only to checked exceptions**. An override can throw any `RuntimeException` or `Error` without declaring it and regardless of what the parent declared, because callers were never compelled to handle unchecked exceptions. So: ```java class F extends A { @Override void read() { // legal throw new IllegalStateException(); // unchecked, no declaration needed } } ``` ## Connection to a bigger principle This is the **Liskov Substitution Principle** in action: a subtype must not strengthen preconditions or weaken postconditions, and 'might throw a new checked failure the caller can't see' would weaken the postcondition guarantee. Java bakes the checked-exception portion of this into the compiler; the unchecked and behavioral parts are left to the programmer.
- Can an override declare zero checked exceptions even if the parent declared some?Yes. Declaring fewer (or none) is always allowed — it only strengthens the guarantee for callers, which is safe.
- Does this rule constrain unchecked exceptions an override throws?No. RuntimeException and Error subclasses can be thrown freely by an override regardless of the parent's throws clause, because callers were never required to handle them.
saying these in an interview costs you the question
- Thinking an override may add any new checked exception
- Believing the rule also restricts unchecked exceptions
- Assuming the override must declare exactly the same throws list
- Confusing this with method overloading (the rule is about overriding)