Detailed explanation
Java’s exception hierarchy starts with java.lang.Throwable, which extends Object. Only objects whose classes extend Throwable can be thrown using throw or handled using catch. Throwable provides facilities such as a message, a cause, and a stack trace, helping developers understand what failed and where. Its two main subclasses are Error and Exception. This hierarchy matters because it determines compiler checks, which catch blocks can handle a failure, and how methods communicate exceptional conditions to callers.
Error represents serious problems that ordinary application code is generally not expected to recover from. Examples include OutOfMemoryError and StackOverflowError, both subclasses of VirtualMachineError. Errors are unchecked, so the compiler does not require methods to catch or declare them. Saying errors “cannot be caught” is incorrect: Java permits catching them, but doing so is usually inappropriate because the application may not be able to continue safely. Exception represents conditions that an application might handle, although extending Exception does not guarantee that recovery is possible.
Within the Exception branch, RuntimeException and its subclasses are unchecked; other Exception subclasses are checked. Checked examples include IOException and SQLException. If code can throw a checked exception, it must handle it with an appropriate catch block or declare it with throws, allowing callers to take responsibility. RuntimeException subclasses include NullPointerException, IllegalArgumentException, and IllegalStateException. They commonly indicate programming errors or invalid usage and do not have this catch-or-declare requirement. Checked exceptions are not a separate class named CheckedException; “checked” describes a compiler-enforced category.
At runtime, Java searches for a compatible handler as an exception propagates through method calls. A catch block can handle its declared type and any subtype. In the given example, IllegalStateException extends RuntimeException, so catch (RuntimeException e) handles it and prints “bad state”. When multiple catch blocks follow a try, subclass handlers must precede superclass handlers; otherwise, the narrower handler is unreachable and compilation fails. Interviewers typically look for the hierarchy, accurate checked-versus-unchecked rules, suitable examples, and awareness that catch (Exception e) excludes Error, while catch (Throwable t) includes both branches.
Key points to remember
- Throwable extends Object and is the root of Java’s throwable hierarchy.
- Throwable’s main branches are Error and Exception.
- Error, RuntimeException, and their subclasses are unchecked.
- Checked exceptions must be caught or declared with throws.
- Catch blocks match subtypes; place specific handlers before general handlers.
Common mistakes candidates make
- Saying all Exception subclasses are checked, ignoring RuntimeException.
- Claiming Error cannot be caught instead of explaining why catching it is generally discouraged.
- Placing catch (Exception e) before a handler for one of its subclasses.
Likely follow-up questions
What is the difference between throw and throws?
throw is a statement that explicitly throws a Throwable object. throws appears in a method or constructor declaration to list exceptions that may propagate to its caller; it does not itself throw anything.
How do you create a custom checked or unchecked exception?
Extend Exception for a custom checked exception, or RuntimeException for a custom unchecked exception. Choose based on whether callers should be required to handle or declare the condition, and provide constructors that preserve useful messages and causes.
Does a checked exception happen at compile time?
No, both checked and unchecked exceptions are thrown at runtime. For checked exceptions, the compiler verifies that potentially thrown exceptions are caught or declared.
Interview tip: Draw the Throwable tree, give one example per category, and use the provided code to explain subtype-based catch matching.
