Java Exception Types and Hierarchy Explained with Examples

Java represents thrown failures as objects belonging to the Throwable hierarchy.

Lesson 65 of 127Intermediate13 min read

Java represents thrown failures as objects belonging to the Throwable hierarchy. The two main branches are Error and Exception; RuntimeException is a branch of Exception. This structure determines which failures have compile-time handling obligations and which catch blocks can match them. It does not decide whether a particular application can recover. Learn the hierarchy together with common examples, causes, and handling boundaries so an exception name becomes useful diagnostic information rather than a label to suppress.

Throwable, Error, and Exception

Throwable is the base type accepted by throw and catch. Error commonly represents serious runtime or environment problems for which ordinary application recovery is not appropriate, such as an exhausted stack. Exception describes failures that application code more commonly anticipates. Avoid catching Throwable casually: that includes errors your operation may not be able to handle safely. Catch a meaningful exception category at a boundary where you can recover, translate, or report the failure.

Checked exceptions create a compilation obligation

A throwable type outside the RuntimeException and Error families is checked. Code that can throw a checked exception normally must catch it or declare it with throws. IOException is a common example when reading files. The compiler's obligation does not mean the failure must happen every time, and a throws declaration does not handle it. It tells callers that they must participate in the checked exception contract.

Unchecked exceptions still require judgment

RuntimeException subclasses are unchecked, so ordinary callers do not have the same catch-or-declare requirement. NumberFormatException can signal invalid text, NullPointerException can signal missing required state, and IllegalArgumentException can reject a domain input. Some are programming defects and others are expected input failures. The checked distinction is a language rule, not a universal severity ranking. Handle anticipated bad input where a useful response is available.

Common exception families at a glance

TypeTypical meaning
IOExceptionA checked input/output operation failed
NumberFormatExceptionText cannot represent the requested number
IndexOutOfBoundsExceptionA requested position is outside its valid range
IllegalArgumentExceptionAn argument violates the operation contract
IllegalStateExceptionThe object cannot perform the operation in its current state
ArithmeticExceptionAn invalid arithmetic operation occurred
UnsupportedOperationExceptionThe requested operation is not supported

A superclass catch can match several subclasses, but broader matching also requires a broader recovery policy. Do not turn all these meanings into the same default value just because one catch can technically intercept them.

Inheritance and causes describe different relationships

An exception's superclass describes its type category. Its cause describes another failure that led to this particular failure object. An IOException can be the cause of an IllegalStateException without becoming that exception's superclass. When translating an error into a domain-specific exception, retain the cause so diagnostics can locate the original failure. A message alone may lose the stack and type information needed to distinguish an invalid file from an unrelated state problem.

Choose narrow handling and preserve context

Place a catch where you know what the failure means to that operation. A missing optional configuration file may permit a documented fallback, while a missing required export file should produce a failure response. A broad catch that reports success conceals broken work. Order subclass catches before superclass catches when using separate clauses, because an earlier broad clause would make a later narrower one unreachable. Follow exception flow to see how matching and cleanup work together.

Practice tasks and checks

Classify IOException, IllegalArgumentException, and StackOverflowError by their hierarchy branch and checked status. Then change CheckedFileFailure so creation succeeds but the read path points to an existing file, and describe the normal outcome you would add. Keep fixture cleanup separate from the read's handling contract. In ExceptionCause, inspect the cause message as well as its type and explain why copying only the message would lose information. Finally, design two different missing-file policies: an optional preferences file and a required document export. Write which boundary owns each decision. The same exception type can require different responses because the application's requirement, not the type name alone, determines recovery.

Java Summary

  • Type inheritance and exception cause chains describe different relationships.
  • Checked status is a compiler rule, not a severity ranking.
  • Handle failures where the operation has a meaningful recovery or reporting policy.
  • Continue with exception control flow when these examples are clear.

Java Examples

Each example shows the code, the output it produces and what each part does.

Example 1

Inspect an actual exception ancestry

Save this program as ExceptionAncestry.java. Compile it with javac ExceptionAncestry.java and run it with java ExceptionAncestry.

Expected output:

The Class object starts at ArithmeticException. Each iteration prints the current type and moves to its superclass. The assignability condition stops before Object, which is not a Throwable type. This demonstrates that an arithmetic failure is a RuntimeException and also an Exception through inheritance. The program inspects declarations rather than deliberately performing division by zero, so no thrown failure is needed to reveal the type relationship.

Java
public class ExceptionAncestry {
    public static void main(String[] args) {
        Class<?> type = ArithmeticException.class;
        while (Throwable.class.isAssignableFrom(type)) {
            System.out.println(type.getSimpleName());
            type = type.getSuperclass();
        }
    }
}
Output
ArithmeticException
RuntimeException
Exception
Throwable
Example 2

Handle a checked missing-file failure

Save this program as CheckedFileFailure.java. Compile it with javac CheckedFileFailure.java and run it with java CheckedFileFailure.

Expected output:

The new temporary directory contains no missing.txt file, so reading that path raises an IOException subtype. The catch provides a deterministic demonstration response without exposing a machine-specific path. Directory creation and deletion can themselves fail, which is why main still declares IOException. Catching the read does not erase the checked obligations of other file operations outside that catch. The finally block removes the empty temporary fixture.

Java
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
public class CheckedFileFailure {
    public static void main(String[] args) throws IOException {
        Path directory = Files.createTempDirectory("exception-demo-");
        try {
            Files.readString(directory.resolve("missing.txt"));
        } catch (IOException error) {
            System.out.println("Required file unavailable");
        } finally {
            Files.delete(directory);
        }
    }
}
Output
Required file unavailable
Example 3

Preserve the original cause when translating

Save this program as ExceptionCause.java. Compile it with javac ExceptionCause.java and run it with java ExceptionCause.

Expected output:

load constructs a contextual unchecked exception while retaining the original I/O cause. The catch prints the translated operation message and then the cause's type. These are different layers of the same failure, not two unrelated errors. A full diagnostic log could include the complete throwable chain. Preserving the cause is especially useful when a higher-level service must express a failure in its own vocabulary.

Java
import java.io.IOException;
public class ExceptionCause {
    static void load() {
        IOException original = new IOException("Input interrupted");
        throw new IllegalStateException("Catalog not loaded", original);
    }
    public static void main(String[] args) {
        try {
            load();
        } catch (IllegalStateException error) {
            System.out.println(error.getMessage());
            System.out.println(error.getCause().getClass().getSimpleName());
        }
    }
}
Output
Catalog not loaded
IOException

Java FAQ

Is every Exception checked?

No. RuntimeException and its subclasses are unchecked even though they belong to Exception. The checked classification excludes that family and the Error family.

Should an application catch Error to continue?

Usually not as an ordinary recovery strategy. Error can signal conditions such as resource exhaustion where continuing normally is unsafe. A specialized boundary may report a failure, but it should not pretend the operation succeeded.

Is NullPointerException checked or unchecked?

Unchecked: it extends RuntimeException, so the compiler never forces you to catch it. It nearly always signals a bug to fix rather than a condition to handle. Since Java 14, its message explains what was null, for example Cannot invoke "String.length()" because ... is null.

Should I catch Exception or Throwable?

Avoid catching Throwable, because it also catches Errors such as OutOfMemoryError. Catching Exception is reasonable at a top-level boundary, such as a request handler or main, where you log the failure and report it. Inside ordinary methods, catch the specific types you can actually handle.

Why are checked exceptions controversial?

They make failure cases visible in method signatures, which helps callers. Critics point out that they add boilerplate, don't work smoothly with lambdas and streams, and tempt developers to catch and ignore them. Many modern frameworks therefore wrap checked exceptions in unchecked ones at their boundaries.

Java Exercises

Answer each one and check it instantly. If you get stuck, open the hint before the answer.

Multiple choiceeasy

Which branch contains ArithmeticException?

Multiple choicemedium

What does a throws declaration do?

Java Quiz

2 questions to check what you learned.

  1. What is an exception cause?

    • The earlier failure leading to this failure
    • Always its superclass
    • Always its message string
  2. Where should a useful catch normally be placed?

    • At a boundary that understands recovery or reporting
    • Around every statement blindly
    • Only inside the constructor