How does the throws clause interact with method overriding — what can an overriding method declare?
answer
- Override: same, narrower, fewer, or none — never broader
- Driven by Liskov substitutability
- Unchecked exceptions are unrestricted in overrides
- Multiple supertypes => intersection of allowed checked exceptions
- Constructors must DECLARE super-constructor's checked exceptions (opposite)
basics
~10 sAn overriding method may not declare new or broader checked exceptions than the method it overrides. It can declare the same ones, narrower subtypes, fewer, or none — but never widen the checked-exception contract.
solid answer
~40 sWhen you override a method, the override's throws clause is constrained by the parent (or interface) method's clause. The rule: an overriding method must not declare any checked exception that is broader than, or not present in, the overridden method's throws list. It can declare the same checked exceptions, narrower subtypes of them, a subset, or none at all. This preserves substitutability (Liskov): code calling through the supertype reference handles only the supertype's declared exceptions, so a subtype must not surprise it with new checked ones. Unchecked exceptions are not restricted — an override can throw any RuntimeException regardless of the parent. A concrete example: if the parent declares throws IOException, the override may declare IOException, FileNotFoundException (a subtype), or nothing, but not Exception (broader) or SQLException (unrelated checked).
go deeper
Recognizes that an override cannot just add a new checked exception, even if unsure of the exact subtype nuances.
States the full rule (same/narrower/fewer/none, never broader), gives valid and invalid examples, and exempts unchecked exceptions.
Explains the rule via Liskov substitution and substitutability of supertype references, and handles the multiple-interface intersection case.
Uses the constraint when designing interface hierarchies and SPI contracts, anticipating how implementers' failure modes must fit the declared surface, and weighs checked-exception contracts against unchecked-based designs.
## Setup: what overriding is **Overriding** is when a subclass (or implementing class) provides its own version of a method that a superclass or interface already defines, with the same name and parameter types. At runtime, a call through a supertype reference dispatches to the subtype's version (dynamic dispatch). For this to be safe, the subtype's method must be **substitutable** for the supertype's — callers written against the supertype must not break. ## The throws rule for overrides An **overriding method may not broaden the checked-exception contract**. Concretely, every checked exception the override declares in its `throws` clause must be the same as, or a **subtype of**, some checked exception declared by the overridden method. The override **may**: - declare the **same** checked exceptions, - declare **narrower** ones (subtypes of the parent's), - declare **fewer** (a subset), - declare **none** at all. The override **may not**: - declare a checked exception **not covered** by the parent's clause (e.g. an unrelated checked type), - declare a **broader** checked exception (a supertype of what the parent declared, including `Exception` or `Throwable`). ## Why — substitutability Consider a caller holding a supertype reference: ```java Reader r = getReader(); // could be any subtype try { r.read(); // Reader.read() declares IOException } catch (IOException e) { ... } ``` The caller only prepared to handle `IOException` because that's all the *supertype* promised. If a subtype's override could declare `throws SQLException`, the caller would suddenly receive a checked exception it never planned for — defeating compile-time safety. So the language forbids widening the checked contract. Declaring **narrower or fewer** is fine: the caller's `catch (IOException e)` still covers a `FileNotFoundException`, and handling *fewer* exceptions never surprises anyone. ## Unchecked exceptions are unrestricted Because unchecked exceptions (`RuntimeException`, `Error` and subclasses) are never part of the enforced contract, an override can throw **any** of them regardless of the parent's clause. The rule constrains **checked** exceptions only. ## Worked examples Parent: ```java class Base { void op() throws IOException { } } ``` Valid overrides: ```java void op() throws IOException { } // same void op() throws FileNotFoundException { } // subtype of IOException void op() { } // none — allowed void op() throws IllegalStateException { } // unchecked — always allowed ``` Invalid overrides (compile errors): ```java void op() throws Exception { } // broader than IOException void op() throws SQLException { } // unrelated checked exception ``` ## Interfaces and multiple inheritance of type When a method implements/overrides declarations from multiple supertypes (e.g. several interfaces), the implementing method may only declare checked exceptions allowed by **all** of them — effectively the intersection of what each permits. If the interfaces declare disjoint checked exceptions, the implementer can declare none of the conflicting ones. ## Constructors are different Note the override rule is about methods. Constructors aren't overridden, but a subclass constructor's `throws` clause **must include** the checked exceptions thrown by the superclass constructor it implicitly/explicitly calls — a separate, opposite-feeling requirement. ## Deriving the answer The single principle to remember: *an override can only keep or shrink the checked-exception promise, never grow it* — because callers coded to the supertype's promise must never be ambushed. Unchecked exceptions sit outside the promise entirely.
- Parent declares throws IOException. Can the override declare throws Exception?No. Exception is a supertype of IOException, so it broadens the checked-exception contract and the override won't compile. It could declare IOException, a subtype like FileNotFoundException, or nothing.
- Does this rule apply to unchecked exceptions?No. An override can throw any RuntimeException or Error regardless of the parent's throws clause, since unchecked exceptions are not part of the enforced contract.
saying these in an interview costs you the question
- Saying an override can add any new checked exception
- Thinking the override must declare the exact same exceptions
- Applying the no-broaden rule to unchecked exceptions
- Confusing the override rule with the constructor rule (which requires declaring)