View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All

Exception Hierarchy in Java: The Secret to Cleaner Code You Need Now!

By Pavan Vadapalli

Updated on Jul 04, 2025 | 18 min read | 18.86K+ views

Share:

Did you know? Java runs over 95% of enterprise-level applications and is installed on more than 1 billion desktop systems and 3 billion mobile devices worldwide. With this scale of usage, understanding the Java Exception Hierarchy is essential for writing code that can handle errors precisely and consistently across diverse environments.

Exception Hierarchy in Java defines a clear structure for handling errors by grouping exceptions into a class hierarchy. This hierarchy helps developers manage errors precisely and write reliable Java applications that handle both runtime and checked exceptions effectively. To implement this, developers rely on tools like the JDK, IntelliJ, or Eclipse IDE, and debugging utilities that aid in managing exceptions efficiently.

In this blog, you will learn about the exception hierarchy in Java, its key components, and how to use it to write maintainable code.

If you are seeking to enhance your Java skills and refine your ability to write clean, efficient code, consider enrolling in upGrad’s Online Software Development Courses. Start today to build a solid foundation and advance your career opportunities!

Understanding Exception Hierarchy in Java: An Overview

Exception Hierarchy in Java is a structured classification under the Throwable class that organizes all error and exception types. It branches into Error for serious system failures and Exception for conditions that programs can handle. Further, exceptions are divided into checked and unchecked exceptions based on compile-time enforcement. This design enforces clear and consistent exception handling in Java applications.

Want to get better at exception handling in Java and write cleaner code? Explore upGrad’s tech courses designed to help you gain hands-on experience with practical projects!

Let’s now explore each core component of Java’s exception hierarchy: Throwable, Exception, and Error to understand how they fit into Java’s error handling model.

1. Throwable - The Root of All Exceptions and Errors

The Throwable class is the parent of every exception and error in Java. It is defined in java.lang package and extends directly from the Object class. Any object that is intended to represent an error condition or an exceptional event must be a subclass of Throwable.

This class provides several useful methods that help inspect what went wrong when an exception or error occurs:

  • getMessage(): Returns a descriptive message that explains what went wrong.
  • getCause(): Returns the underlying cause of the throwable, if one was set during construction.
  • printStackTrace(): Displays the sequence of method calls that led to the error or exception.

There are two direct subclasses of Throwable:

  • Exception: Used to represent application-level conditions that can be caught and handled.
  • Error: Used to signal critical failures in the Java Virtual Machine or runtime environment, which are not typically handled by application code.

Only objects of type Throwable (or its subclasses) can be used with the throw statement. If a class does not inherit from Throwable, the Java compiler will not allow it to be thrown as an exception.

Also Read: Hierarchical Inheritance in Java: Key Concepts, Examples, and Practical Uses

2. Exception - Represents Recoverable Conditions

The Exception class is used to model problems that a program may reasonably handle during normal operation. These can include file access errors, invalid input from users, or communication failures. When such conditions occur, they are not fatal to the application, and developers can write code to manage or recover from them.

There are two main categories of exceptions in Java: built-in exceptions and user-defined exceptions.

1. Built-in Exceptions: Built-in exceptions are provided by the Java API to handle common failure conditions during program execution. These are further categorized into checked and unchecked exceptions.

a) Checked Exceptions

Checked exceptions are subject to compile-time checks. If a method can throw a checked exception and does not catch it internally, the method must declare it using the throws keyword. These exceptions usually relate to external conditions beyond the control of the application, such as file system access or database operations.

Examples of checked exceptions:

  • IOException: Signals an input/output operation failure, such as reading a file or closing a stream.
  • FileNotFoundException: Indicates that a file specified in the program does not exist.
  • SQLException: Occurs when there is a problem executing SQL commands or connecting to a database.
  • ParseException: Thrown when input data does not match the expected format during parsing.
  • InterruptedException: Indicates that a thread was interrupted while it was sleeping, waiting, or blocked.

By enforcing compile-time handling of these exceptions, Java ensures that the program includes logic to deal with likely failures.

b) Unchecked Exceptions (Runtime Exceptions)

Unchecked exceptions are those that inherit from the RuntimeException class. These exceptions are not checked by the compiler, which means the programmer is not required to declare or catch them. They often result from Java programming mistakes, such as incorrect logic, invalid input assumptions, or misuse of APIs.

Examples of unchecked exceptions:

  • NullPointerException: Thrown when a method is called on a null object reference.
  • ArrayIndexOutOfBoundsException: Occurs when trying to access an array with an index that is outside its valid range.
  • IllegalArgumentException: Thrown when a method receives an argument that is not acceptable.
  • NumberFormatException: A subtype of IllegalArgumentException, thrown when trying to convert a string to a numeric type and the string is not properly formatted.
  • ClassCastException: Occurs when an object is cast to a class that it does not belong to.

While unchecked exceptions can be caught and handled, they are not enforced by the compiler. Developers are responsible for identifying and avoiding them through proper logic and input validation.

2. User-Defined Exceptions: Java allows developers to create custom exceptions to represent specific application-level errors. These are created by extending the Exception class (for checked exceptions) or the RuntimeException class (for unchecked exceptions), depending on whether the exception should be enforced at compile time.

Methods to retrieve exception information:

  • printStackTrace(): Prints the full stack trace, including the exception name, message, and exact code location.
  • toString(): Returns a brief description combining the class name and the message.
  • getMessage(): Retrieves only the detailed message, useful for logging or user-facing output.

Custom exceptions are typically declared when built-in types do not provide sufficient context or clarity for the specific error condition being handled.

Checked vs Unchecked Exceptions: Key Differences

Aspect

Checked Exceptions

Unchecked Exceptions

Compiler Enforcement Must be either caught or declared using throws at compile time. No requirement to catch or declare; the compiler allows code to compile without explicit handling.
Type Hierarchy Direct subclasses of Exception, excluding RuntimeException. Subclasses of RuntimeException.
Failure Origin Typically triggered by external failures such as IO, database, or network issues. Often stem from internal programming errors like logic flaws or misuse of APIs.
Code Robustness Intent Designed to enforce predictable error recovery, making APIs safer to use in critical environments. Encourages defensive programming, where errors should be avoided rather than explicitly handled.
Common Use Cases File handling, checked parsing, JDBC operations, reflection, and thread interruption. Null checks, collection access, arithmetic operations, and casting.
Best Practice Should be used when recovery is realistically possible by the calling code. Should be avoided by writing fault-tolerant and validated code; use try-catch sparingly.
API Design Implications Libraries that expose checked exceptions force consumers to consciously handle failure cases. APIs using unchecked exceptions promote simpler method signatures but rely on proper documentation.

Strengthen your programming skills with upGrad’s Core Java Basics Course to gain expertise in variables, data types, loops, and OOP principles. Perfect for aspiring developers and professionals looking to transition to Java. Get started today!

Also Read: 50 Java Projects With Source Code in 2025: From Beginner to Advanced

3. Error - Indicates Serious Failures in the JVM

The Error class is used to signal problems that occur at the level of the Java Virtual Machine (JVM) or the underlying hardware. These problems are not caused by incorrect application logic and usually cannot be anticipated or recovered from. As a result, application code is not expected to catch or handle these errors.

When an error occurs, it often indicates that the JVM is in an unstable state. Handling such conditions may not be useful and can sometimes worsen the situation.

Examples of errors:

  • VirtualMachineError: Superclass for critical JVM issues, such as internal resource exhaustion.
  • LinkageError: Occurs when there are problems with class loading, such as mismatched or corrupted class versions.
  • AssertionError: Thrown when an assertion fails, typically used in debugging and testing scenarios.
  • OutOfMemoryError: Thrown when the JVM cannot allocate memory for new objects.
  • StackOverflowError: Occurs when a program recurses too deeply and exhausts the stack space.

These are unchecked errors, meaning the compiler does not enforce them and can occur at any point during execution. Applications rarely handle them, as they indicate conditions that typically require the JVM to be terminated or completely restarted.

Hierarchy Diagram of the Exception Hierarchy:

To handle exceptions effectively, it’s important to understand how Java organizes them in a class hierarchy. Below is a structured view of how Throwable, Error, and Exception are related.

java.lang.Object  
 └── java.lang.Throwable  
     ├── java.lang.Exception  
     │   ├── java.lang.RuntimeException  
     │   │   ├── NullPointerException  
     │   │   ├── IllegalArgumentException  
     │   │   ├── ArrayIndexOutOfBoundsException  
     │   │   └── ClassCastException  
     │   ├── IOException  
     │   │   ├── FileNotFoundException  
     │   │   └── EOFException  
     │   ├── SQLException  
     │   ├── InterruptedException  
     │   └── ParseException  
     └── java.lang.Error  
         ├── VirtualMachineError  
         │   ├── OutOfMemoryError  
         │   └── StackOverflowError  
         ├── AssertionError  
         └── LinkageError  

Explanation:

  • Object is the base class for all Java classes.
  • Throwable branches into two types: Exception and Error.
  • Exception covers conditions a program might catch and handle.
  • It includes both checked exceptions (like IOException, SQLException) and unchecked exceptions (RuntimeException and its subclasses).
  • Error represents serious failures typically related to the JVM, which are not meant to be caught or handled by applications.
Note: Error vs Exception in Java refers to the structural and behavioral distinction within the Throwable hierarchy. Errors are serious, unrecoverable conditions caused by JVM failures and are unchecked. Exceptions represent application-level issues that can be handled programmatically and are classified as checked or unchecked.

Coverage of AWS, Microsoft Azure and GCP services

Certification8 Months

Job-Linked Program

Bootcamp36 Weeks

Looking to advance your career in Java and modern cloud technologies? Enroll in upGrad’s Master the Cloud and Lead as an Expert Cloud Engineer to acquire expertise in AWS, Azure, and Google Cloud. Begin your professional transformation today!

Also Read: What is Hashtable in Java? Explained with Examples

Let’s understand how exception handling works in Java through clear examples.

Practical Examples of Exception Handling in Java

Java’s exception hierarchy classifies errors into checked and unchecked exceptions, enabling precise control over different failure scenarios. Using try, catch, and finally blocks, developers can manage issues like IOException or NullPointerException to maintain application stability and support graceful recovery.

Below are practical examples illustrating key exception handling techniques in Java:

1. Catching a Single Exception

In Java, exceptions are objects representing abnormal conditions that disrupt normal execution. A typical approach to handle such conditions is using a try-catch block, where the try block contains code that may throw an exception, and the catch block defines how to handle it.

Code Example:

public class SingleExceptionExample {
    public static void main(String[] args) {
        int[] numbers = {1, 2, 3};
        try {
            // Attempt to access an invalid index
            System.out.println(numbers[5]);
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("Caught an exception: " + e);
        }
    }
}

Explanation:

  • The array numbers have elements at indices 0 to 2. Accessing numbers[5] causes an ArrayIndexOutOfBoundsException.
  • The JVM throws the exception, which is caught by the matching catch block.
  • The catch block prints the exception, allowing the program to continue instead of crashing.

Output: This confirms that the exception was caught and handled properly, avoiding abrupt termination.

Caught an exception: java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 3

2. Catching Multiple Exceptions

Java 7 introduced multi-catch, allowing a single catch block to handle multiple exception types. This simplifies error handling when different exceptions require the same logic, reducing duplication and improving maintainability.

Code Example:

public class MultiCatchExample {
    public static void main(String[] args) {
        try {
            String input = "xyz";
            int number = Integer.parseInt(input); // Throws NumberFormatException
            int result = 10 / 0;                  // Would throw ArithmeticException
        } catch (NumberFormatException | ArithmeticException e) { // Java 7+ feature
            System.out.println("Caught an exception: " + e);
        }
    }
}

Explanation:

  • The string "xyz" is not a valid integer, so Integer.parseInt(input) throws a NumberFormatException.
  • The division by zero (10 / 0) would trigger an ArithmeticException, but it is never reached because the first exception halts the try block.
  • The catch block handles both exceptions using multi-catch (|), and its available since Java 7.
  • The variable e is implicitly final, so it cannot be reassigned inside the block.
  • Only the first exception thrown is caught; execution does not resume within the try block after the exception.

Output: This demonstrates how multi-catch enables unified handling for multiple exception types, enhancing readability and reducing boilerplate.

Caught an exception: java.lang.NumberFormatException: For input string: "xyz"

Note: In a multi-catch block, the exception variable e is implicitly final and cannot be reassigned within the catch block. This design prevents ambiguity when handling multiple exception types. Use multi-catch only when all exceptions require the same handling logic.

Are you ready to accelerate your career in the tech world? upGrad’s Professional Certificate Program in Cloud Computing and DevOps offers hands-on training with AWS, Azure, and Google Cloud. Gain expertise in Docker and Kubernetes to enhance your tech skills and advance your career!

Also Read: A Complete Guide to Java Keywords

Now let’s see how the JVM handles an exception when it remains uncaught in the application code.

JVM’s Default Handling of Exception Hierarchy in Java

If an exception is not caught in the current method or its call stack, the JVM creates an exception object and searches for a matching handler. If none is found, it prints the stack trace to System.err and terminates the thread where the exception occurred.

The process followed by the JVM includes the following steps:

Step 1. Exception Object Creation

The JVM creates an exception object representing the error. This is an instance of a specific class, such as NullPointerException, IOException, or ArithmeticException. The object contains:

  • Exception type: Identifies the exact class of the exception.
  • Message: A brief description of the issue, either default or custom.
  • Stack trace: A snapshot of the call stack at the point the exception occurred, useful for debugging.

Step 2. Search for an Exception Handler

After creating the exception object, the JVM looks for a suitable catch block:

  • It starts with the method where the exception was thrown.
  • If no handler is found there, the search continues up the call stack, moving through each calling method.
  • The JVM stops at the first matching catch block where the exception type matches or is a subclass of the thrown type.
  • If no match is found in the entire call chain, the search ends.

Step 3. Handling or Program Termination

  • If a matching handler is found, control is transferred to that catch block, which receives the exception object. After it executes, the program continues based on the control flow.
  • If no handler is found, the JVM’s default exception handler is invoked:
    • The current thread is terminated (not the entire program, unless it's the main thread).
    • The exception’s type, message, and stack trace are printed to System.err.

All exceptions, whether checked or unchecked, are subclasses of the Throwable class. Errors such as OutOfMemoryError follow the same propagation mechanism but are generally not intended to be caught or handled in application code.

Note: Uncaught exceptions in non-main threads do not stop the entire JVM; only the affected thread is terminated. For centralized handling of such exceptions across threads, use Thread.setDefaultUncaughtExceptionHandler(). This allows logging or cleanup logic to run even when no local catch block is present.

Enhance your Java programming skills with upGrad’s Java Object-oriented Programming Course. In just 12 hours of learning, explore key OOP principles like classes, objects, inheritance, and abstraction. Enroll now and advance your Java expertise!

Also Read: 30+ Exception Handling Interview Questions and Answers in 2025 [Freshers & Experienced]

Let’s now explore the key techniques programmers use to manage exceptions within Java’s hierarchy, ensuring controlled error handling and maintaining application stability.

upGrad’s Exclusive Software Development Webinar for you –

SAAS Business – What is So Different?

 

How Do Programmers Handle an Exception Hierarchy in Java?

Java provides structured mechanisms to handle exceptions and prevent abrupt program termination caused by unhandled errors. These tools enable developers to catch, manage, and respond to various exception types, maintain control over program flow, and ensure application stability.

Programmers use the following key techniques to manage exceptions within Java’s hierarchy:

  • Try-Catch Blocks: The primary method for handling exceptions. Code that may throw exceptions is placed inside a try block, followed by one or more catch blocks that handle specific exception types. Multiple catch blocks allow precise responses for different errors. More specific exceptions should appear before general ones to avoid unreachable code.
  • Finally Block: An optional block executed after the try and catch blocks, regardless of whether an exception occurred. It is typically used for resource cleanup, such as closing files or database connections, ensuring that critical operations execute even if exceptions disrupt normal flow.
  • Throws Keyword: Methods that may throw checked exceptions they do not handle must declare them using the throws keyword. This declaration enforces compile-time checking, requiring callers to handle or re-declare these exceptions. Unchecked exceptions do not require a declaration and can propagate unchecked.
  • Throw Keyword: Used to explicitly throw exceptions within code to signal error conditions detected during execution. This allows developers to enforce business rules or validation logic by triggering exceptions programmatically.
  • Custom Exceptions: Developers can define application-specific exception classes by extending Exception or RuntimeException. This enables clearer error categorization and more precise handling strategies customized to the domain logic.
  • Exception Chaining: When re-throwing exceptions, the original cause can be passed to the new exception via constructors. This preserves the full stack trace and exception context, aiding debugging, especially in layered applications where low-level exceptions are wrapped in higher-level ones.

These techniques collectively support structured, maintainable, and performant error handling aligned with Java’s exception hierarchy.

Code Example:

public class DataAccessException extends Exception {
    public DataAccessException(String message, Throwable cause) {
        super(message, cause);
    }
}

public class DatabaseService {
    public void saveData(Object data) throws DataAccessException {
        try {
            // Simulate a database operation that throws SQLException
            throw new java.sql.SQLException("Database connection failed!");
        } catch (java.sql.SQLException e) {
            // Wrap SQLException in a custom exception, preserving the cause
            throw new DataAccessException("Failed to save data due to database error.", e);
        }
    }
    
    public static void main(String[] args) {
        DatabaseService service = new DatabaseService();
        try {
            service.saveData(new Object());
        } catch (DataAccessException e) {
            e.printStackTrace();
        }
    }
}

Explanation:

  • DataAccessException extends Exception and adds a constructor that accepts a message and a Throwable cause, enabling exception chaining.
  • The saveData method simulates a database call that throws a checked SQLException.
  • This SQLException is caught inside the catch block and re-thrown as a DataAccessException, passing the original exception e as the cause.
  • This chaining maintains the full stack trace and original exception details.
  • In main(), the DataAccessException is caught and its stack trace is printed, revealing both the custom message and the underlying SQLException.

Output:

DataAccessException: Failed to save data due to database error.
   at DatabaseService.saveData(DatabaseService.java:11)
   at DatabaseService.main(DatabaseService.java:19)
Caused by: java.sql.SQLException: Database connection failed!
   at DatabaseService.saveData(DatabaseService.java:9)
   ... 1 more

Explanation:

  • The output shows the DataAccessException thrown by saveData() with the provided message.
  • The stack trace includes the cause (SQLException), showing the original error and where it occurred.
  • The Caused by section preserves the original exception type and message, which is critical for debugging and understanding the root cause.
  • The line ... 1 more shows that one stack frame from the cause (SQLException) is omitted to avoid repeating frames already shown in the outer exception’s trace, keeping it concise.
  • This demonstrates how exception chaining keeps full context across layers while allowing higher abstraction in error handling.
Note: The difference between throw and throws in Java is that throw raises an exception inside a method. In contrast, throws declares exceptions a method can pass to its caller for compile-time checking.

Want to build AI-powered applications using Java and modern tools? Enroll in upGrad’s AI-Driven Full-Stack Development program and learn to develop smart software using OpenAI, GitHub Copilot, Bolt AI, and more.

Also Read: Top 10 Free Java Courses with Certificates for In-Demand Java Jobs

Enhance Your Java Coding Skills with upGrad!

The exception hierarchy in Java is the class-based structure under the Throwable superclass that defines how all errors and exceptions are organized. It distinguishes critical system failures (Error) from application-level exceptions (Exception) and classifies them further based on compile-time handling. This structure helps developers apply the right exception types, handle failures explicitly, and build stable Java applications.

To apply this knowledge effectively and gain confidence in writing production-grade code, structured learning becomes crucial. This is where upGrad comes in, offering comprehensive Java courses that combine theory with practical coding experience.

Here are a few additional upGrad programs to strengthen your development skills:

Are you struggling to find the right Java software development course to match your goals in 2025? Reach out to upGrad for personalized counseling and valuable insights, or visit your nearest upGrad offline center for more details.

Boost your career with our popular Software Engineering courses, offering hands-on training and expert guidance to turn you into a skilled software developer.

Master in-demand Software Development skills like coding, system design, DevOps, and agile methodologies to excel in today’s competitive tech industry.

Stay informed with our widely-read Software Development articles, covering everything from coding techniques to the latest advancements in software engineering.

References:
https://www.slajobs.com/top-15-facts-about-java/
https://www.cybersuccess.biz/interesting-facts-java-programming-language/

Frequently Asked Questions (FAQs)

1. How does the exception hierarchy in Java support polymorphism?

2. Where does RuntimeException fit in the exception hierarchy in Java?

3. Can we catch Error in the exception hierarchy in Java?

4. What is the use of Throwable methods in the exception hierarchy in Java?

5. Why is Exception preferred over Throwable in catch blocks?

6. How does Java enforce checked exception handling via its hierarchy?

7. What role does IOException play in the exception hierarchy in Java?

8. What is the significance of RuntimeException being unchecked?

9. Are user-defined exceptions part of the exception hierarchy in Java?

10. What happens if two catch blocks target the same level in the exception hierarchy in Java?

11. How is ExceptionInInitializerError related to the hierarchy?

Pavan Vadapalli

900 articles published

Director of Engineering @ upGrad. Motivated to leverage technology to solve problems. Seasoned leader for startups and fast moving orgs. Working on solving problems of scale and long term technology s...

Get Free Consultation

+91

By submitting, I accept the T&C and
Privacy Policy

India’s #1 Tech University

Executive PG Certification in AI-Powered Full Stack Development

77%

seats filled

View Program

Top Resources

Recommended Programs

upGrad

AWS | upGrad KnowledgeHut

AWS Certified Solutions Architect - Associate Training (SAA-C03)

69 Cloud Lab Simulations

Certification

32-Hr Training by Dustin Brimberry

upGrad KnowledgeHut

upGrad KnowledgeHut

Angular Training

Hone Skills with Live Projects

Certification

13+ Hrs Instructor-Led Sessions

upGrad

upGrad

AI-Driven Full-Stack Development

Job-Linked Program

Bootcamp

36 Weeks