skip to content

Exception Hierarchy

The Throwable tree and the checked-versus-unchecked classification it produces. Being able to place a given exception in the tree is standard interview material.

part ofJavaoverview, primer and where to startread it →
on this pageshow

questions

10

What is the difference between a checked and an unchecked exception in Java?

level: juniorimportance: must knowfreq 85%

answer

  1. Checked = Exception but not RuntimeException; compiler-enforced
  2. Unchecked = RuntimeException subtree + Error subtree
  3. Catch-or-declare rule applies only to checked
  4. Checked = recoverable; unchecked = bugs / fatal JVM
  5. RuntimeException extends Exception but is carved out as unchecked

basics

~10 s

A checked exception must be either caught or declared with throws, and the compiler enforces this. An unchecked exception (RuntimeException or Error and their subclasses) is not enforced by the compiler.

solid answer

~40 s

Java splits exceptions into two compiler-enforced categories. A checked exception is any subclass of Exception that is NOT a subclass of RuntimeException (for example IOException, SQLException). For these the compiler enforces a 'catch-or-declare' rule: any code that might throw one must either catch it with try/catch or declare it in the method's throws clause, otherwise the code won't compile. An unchecked exception is RuntimeException and its subclasses (NullPointerException, IllegalArgumentException, etc.) plus Error and its subclasses (OutOfMemoryError). The compiler does not require you to catch or declare these. The practical idea: checked = recoverable conditions the caller should plan for; unchecked = programming bugs or fatal JVM problems you usually can't sensibly recover from at the call site.

go deeper

for a junior

Can state the catch-or-declare rule and give one example of each category (e.g. IOException checked, NullPointerException unchecked).

for a middle

Can place RuntimeException and Error correctly in the hierarchy and explain that 'checked' is a compile-time concept, not runtime.

for a senior

Can explain the design rationale (recoverable vs bug/fatal) and choose the right category when designing an API, plus translate exceptions across layers.

for a principal

Can argue the tradeoffs (boilerplate, leaky abstractions, lambda/stream friction), set a team-wide policy, and explain why modern libraries and Kotlin avoid checked exceptions.

## Background: what an exception is In Java, when something goes wrong at runtime, the program creates an **exception object** and 'throws' it. Throwing means normal execution stops and the JVM looks back up the chain of method calls (the **call stack**) for code that can **handle** the problem with a `try { ... } catch (SomeException e) { ... }` block. If no handler is found, the program crashes and prints a stack trace. ## The exception class hierarchy Everything throwable descends from the class `Throwable`. Below it there are two main branches: ``` Throwable ├── Error (e.g. OutOfMemoryError, StackOverflowError) -> UNCHECKED └── Exception ├── RuntimeException (e.g. NullPointerException, │ IllegalArgumentException, │ ArrayIndexOutOfBoundsException) -> UNCHECKED └── (everything else: IOException, SQLException, ...) -> CHECKED ``` The categorization rule is purely structural: - **Checked** = a subclass of `Exception` that is **NOT** a subclass of `RuntimeException`. - **Unchecked** = a subclass of `RuntimeException`, OR a subclass of `Error`. Note `RuntimeException` itself extends `Exception`, but it (and its descendants) are carved out as unchecked. ## What 'checked' actually means: the catch-or-declare rule The word 'checked' refers to a **compile-time** check the Java compiler performs. If a piece of code can throw a checked exception, the compiler forces you to do one of two things, or your code will not compile: 1. **Catch** it: wrap the call in `try { ... } catch (IOException e) { ... }`. 2. **Declare** it: add `throws IOException` to the enclosing method's signature, pushing the obligation onto whoever calls your method. This is called the **catch-or-declare** (or 'handle-or-declare') requirement. The compiler tracks, for every statement, which checked exceptions could escape, and verifies one of the two options is satisfied. Unchecked exceptions are exempt: you *may* catch them, but the compiler never *requires* it, and you don't have to list them in `throws`. ## Why two categories? The design rationale The original intent: **checked exceptions model recoverable, expected-but-abnormal conditions** that a well-written caller should consciously deal with — a file that doesn't exist, a network connection that drops. By forcing acknowledgment at compile time, the language tries to prevent you from silently ignoring these. **Unchecked exceptions model two other things:** - `RuntimeException` subclasses model **programming errors / bugs** — dereferencing null, passing an illegal argument, indexing past the end of an array. These can occur almost anywhere, so requiring `throws` on every method would be unbearable; and the right fix is usually to correct the code, not to catch the exception. - `Error` subclasses model **serious, usually unrecoverable JVM-level problems** — running out of memory, stack overflow. Application code generally should not try to catch or recover from these. ## The criticism of checked exceptions Checked exceptions are controversial. Common complaints: - **Boilerplate**: long `throws` lists or `try/catch` clutter. - **Leaky abstractions**: a low-level `SQLException` propagates `throws SQLException` up through many layers that shouldn't know about SQL. - **Encourages swallowing**: developers under pressure write empty `catch` blocks (`catch (IOException e) {}`), which hides errors — worse than not checking at all. - **Poor fit with generics, lambdas, and streams**: functional interfaces like `Function` don't declare checked exceptions, so checked exceptions are awkward inside lambdas. Because of this, many modern Java libraries (and other JVM languages such as Kotlin) avoid checked exceptions entirely, wrapping them in unchecked exceptions instead. Java itself never added new checked-exception-style features after the early years. ## Practical guidance - Throw a **checked** exception when the caller can realistically **recover** and you want to *force* them to consider it. - Throw an **unchecked** exception for **programming errors** (invalid arguments, illegal state) and when forcing handling would only add noise. - When crossing an architectural boundary, **translate** a low-level checked exception into a domain-specific exception (often unchecked) so callers don't depend on implementation details — but keep the original as the **cause** (`new MyException("msg", e)`) so the stack trace is preserved.

  • Is RuntimeException checked or unchecked, given that it extends Exception?
    Unchecked. The rule isn't 'extends Exception' alone — RuntimeException and all its subclasses are explicitly carved out of the checked category, so the compiler does not enforce catch-or-declare for them.
  • Where does Error fit?
    Error and its subclasses are unchecked. They represent serious, typically unrecoverable JVM problems (OutOfMemoryError, StackOverflowError) that application code normally should not catch.

saying these in an interview costs you the question

  • Saying unchecked exceptions can't be caught (they can; you just aren't forced to)
  • Claiming Error is a checked exception (it is unchecked)
  • Saying the difference is decided at runtime (it is a compile-time check)
  • Thinking RuntimeException is checked because it extends Exception
  • Believing throws is required for unchecked exceptions

context

open as a page

Name several common RuntimeException types and explain what each one signals about a likely bug in the code.

level: juniorimportance: must knowfreq 72%

basics

~10 s

Common ones: NullPointerException (used a null), IllegalArgumentException (bad argument passed in), IllegalStateException (called at the wrong time), ClassCastException (bad cast), ArrayIndexOutOfBoundsException (index past the array end), and NumberFormatException (parsed text that isn't a number).

open as a page

Describe the Throwable class hierarchy in Java. What are its two main branches and what does each represent?

level: juniorimportance: must knowfreq 75%

basics

~20 s

Throwable is the root of everything you can throw or catch. It splits into Error (serious system problems you shouldn't catch, like running out of memory) and Exception (problems your program can handle, like a missing file or bad input).

open as a page

What is the difference between checked and unchecked exceptions, and how does that distinction map onto the Throwable hierarchy?

level: middleimportance: must knowfreq 80%

basics

~10 s

Checked exceptions must be handled or declared with throws, or your code won't compile. Unchecked ones (RuntimeException and Error) don't force you to do anything. The compiler enforces checked exceptions; it ignores unchecked ones.

open as a page

Given an arbitrary throwable class, how do you determine whether it is checked or unchecked?

level: middleimportance: should knowfreq 55%

basics

~10 s

Look at its ancestry. If it is a subclass of RuntimeException or of Error, it is unchecked. If it is a subclass of Exception but not of RuntimeException, it is checked.

open as a page

What is an Error in Java, how does it differ from an Exception, and what are some common Error types?

level: middleimportance: should knowfreq 58%

basics

~20 s

An Error signals a serious problem — usually from the JVM or environment — that a normal program isn't expected to recover from, like running out of memory. Exceptions are conditions your code can handle; Errors generally aren't. Common Errors: OutOfMemoryError, StackOverflowError, NoClassDefFoundError, AssertionError.

open as a page

When should you design an API to throw a checked exception versus an unchecked one?

level: seniorimportance: should knowfreq 50%

basics

~20 s

Use a checked exception when the caller can reasonably recover and you want to force them to handle it. Use an unchecked exception for programming errors (bad arguments, illegal state) and conditions the caller usually can't fix.

open as a page

Why can only objects whose class extends Throwable be thrown or caught in Java, and what are the practical implications when designing custom exceptions?

level: seniorimportance: should knowfreq 45%

basics

~20 s

The language and JVM require that anything you throw or catch be a Throwable, because Throwable carries the machinery exceptions need — a message, a cause, and the stack trace. So your custom exceptions must extend Throwable (in practice, Exception or RuntimeException).

open as a page

What rule governs the checked exceptions an overriding method may declare in its throws clause?

level: seniorimportance: nice to knowfreq 35%

basics

~10 s

An 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.

open as a page

Why are checked exceptions controversial, and how do modern designs work around their drawbacks?

level: principalimportance: nice to knowfreq 30%

basics

~10 s

Checked exceptions add boilerplate, leak low-level details up through layers, tempt developers to swallow errors, and don't fit lambdas/streams. Modern designs prefer unchecked exceptions, wrap checked ones, and translate them at boundaries.

open as a page