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

Comprehensive Guide to Exception Handling in Java: Best Practices and Examples

By Sriram

Updated on Jan 07, 2025 | 15 min read | 7.3k views

Share:

Did you know that Java powers over 9 million developers globally? Its reliability and scalability make it a favorite for everything from Android apps to complex financial systems. But what happens when things go wrong, like a file not found, invalid user input, or a network failure? That’s where exception handling in Java becomes crucial.

Exception handling allows you to anticipate, catch, and manage these errors, ensuring your application doesn’t crash and burn. Instead, it continues running smoothly, providing a better experience for users.

In this blog, you’ll learn how to master exception handling in Java with examples. From understanding the basics to implementing best practices, it will equip you with the tools to write resilient, error-tolerant code. 

Let’s get started!

What are Exceptions in Java and Their Significance? Understand with Examples

In Java, exceptions are disruptions that occur during the program's execution, preventing it from proceeding normally. These runtime issues don’t have to spell disaster. Instead, Java provides a structured framework for detecting and managing these errors.

By handling exceptions, you can ensure smooth program flow, provide meaningful error messages to users, and safeguard against crashes. 

Let’s explore exception handling in Java in more detail!

Understanding Exceptions in Java

Exceptions in Java are broadly categorized into two types: checked and unchecked exceptions. These categories help you determine which errors must be explicitly handled and which can occur without interrupting the program.

Have a look at the comparison table of both:

Aspect Checked Exceptions Unchecked Exceptions
Definition Exceptions checked at compile time. Exceptions that occur at runtime.
Examples IOException, SQLException ArithmeticException, NullPointerException
Handling Requirement Must be handled using try-catch or declared with throws. No explicit handling required, but can be managed using try-catch.
Occurrence Often caused by external resources like files or databases. Arises from logical errors in the code.

To understand its implementation better, go through the examples given.

1. Checked Exception Example:

import java.io.FileReader;
import java.io.IOException;

public class CheckedExceptionExample {
    public static void main(String[] args) {
        try {
            // Attempting to read a file that may not exist
            FileReader file = new FileReader("nonexistentfile.txt");
        } catch (IOException e) {
            // Handling the IOException
            System.out.println("Error: File not found!");
        }
    }
}

Output:

Error: File not found!

Code Explanation:

  • The FileReader attempts to open a file that doesn’t exist, which triggers an IOException.
  • The compiler forces you to handle the IOException because it’s a checked exception.

2. Unchecked Exception Example:

public class UncheckedExceptionExample {
    public static void main(String[] args) {
        // Attempting to divide by zero
        int result = 10 / 0;  // Triggers ArithmeticException
        System.out.println("Result: " + result);
    }
}

Output:

Exception in thread "main" java.lang.ArithmeticException: / by zero

Code Explanation:

  • Dividing by zero triggers an ArithmeticException at runtime.
  • Unlike checked exceptions, the compiler doesn’t enforce this error but should be addressed logically to prevent program failure.

Hierarchy of Exceptions in Java

Java’s exception system follows a clear hierarchy that starts with the Throwable class. This class has two main subclasses: Error and Exception. This structure helps you understand how to categorize and manage different types of errors.

Here’s an overview of the hierarchy of Java expectation classes:

  • Throwable: The root of all exceptions and errors in Java.
  • Error: Represents severe issues beyond the application’s control (e.g., OutOfMemoryError, StackOverflowError).
  • Exception: Represents application-level issues that can be caught and handled.

Have a look at a code example demonstrating the hierarchy:

public class ExceptionHierarchyExample {
    public static void main(String[] args) {
        try {
            // Attempting to access a null object
            String str = null;
            System.out.println(str.length());  // Triggers NullPointerException
        } catch (NullPointerException e) {
            System.out.println("Caught a NullPointerException!");
        } catch (Exception e) {
            System.out.println("Caught a general Exception!");
        }
    }
}

Output:

Caught a NullPointerException!

Explanation:

  • Accessing a null object triggers a NullPointerException, a RuntimeException subclass.
  • The exception is caught by the specific NullPointerException block first. It would fall back to the general Exception block if not handled there.

By understanding these fundamental concepts of exception handling in Java, you can write resilient, error-free applications. 

 

If you wish to upskill and enhance these in-demand tech concepts, explore upGrad’s comprehensive software development programs from top universities!

 

Now, in any robust application, errors are inevitable — but how you handle them makes all the difference. Let’s see how you do it!

Coverage of AWS, Microsoft Azure and GCP services

Certification8 Months
View Program

Job-Linked Program

Bootcamp36 Weeks
View Program

How Java Facilitates Efficient Exception Handling and Essential Methods

Java, one of the most developer-friendly languages, offers a structured exception-handling framework to tackle errors efficiently without disrupting the program flow. It ensures you’re not just catching errors but managing them intelligently. 

Exception handling in Java includes key constructs like try-catch, finally, throw, and throws, which enable developers to handle errors effectively, combined with robust APIs and tools.

Let’s explore how these mechanisms work and how they prevent abrupt program failures.

1. try-catch: Controlled Error Resolution

  • The try block contains code that might throw an exception.
  • The catch block handles specific exceptions, allowing you to define a response.

Code Example:

public class TryCatchExample {
    public static void main(String[] args) {
        try {
            int result = 10 / 0;  // Triggers ArithmeticException
        } catch (ArithmeticException e) {
            System.out.println("Error: Cannot divide by zero!");
        }
    }
}

Output:

Error: Cannot divide by zero!

In this code example of try-catch in Java, the program gracefully handles the exception instead of crashing and continues.

2. finally: Ensuring Cleanup

The finally block is always executed, regardless of whether an exception occurs, making it ideal for cleanup operations like closing files or releasing resources.

Code Example:

public class FinallyExample {
    public static void main(String[] args) {
        try {
            int[] numbers = {1, 2};
            System.out.println(numbers[5]);  // Triggers ArrayIndexOutOfBoundsException
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("Error: Index out of bounds!");
        } finally {
            System.out.println("Execution complete.");
        }
    }
}

Output:

Error: Index out of bounds!  
Execution complete.

In this example, the ‘finally’ block ensures that critical tasks are completed, even if an exception occurs.

3. throw: Manually Raising Exceptions

  • The throw keyword is used explicitly to raise an exception in the program.
  • It is typically used when a specific condition in your code requires you to generate an error manually.

Code Example:

public class ThrowExample {
    public static void main(String[] args) {
        int age = 15;
        if (age < 18) {
            throw new IllegalArgumentException("Age must be 18 or older.");
        }
    }
}

Output:

Exception in thread "main" java.lang.IllegalArgumentException: Age must be 18 or older.

In the code snippet, when the condition age < 18 is met, the program raises an IllegalArgumentException.

4. throws: Declaring Exceptions

The throws keyword is used to declare the exceptions a method might throw, allowing the caller of the method to handle them.

Code Example:

public class ThrowsExample {
    public static void checkNumber(int number) throws Exception {
        if (number < 0) {
            throw new Exception("Negative number not allowed!");
        }
    }

    public static void main(String[] args) {
        try {
            checkNumber(-5);
        } catch (Exception e) {
            System.out.println("Error: " + e.getMessage());
        }
    }
}

Output:

Error: Negative number not allowed!

Here, the throws keyword informs the caller that checkNumber might throw an exception, which must be handled explicitly in the calling method.

This structured way of exception handling in Java prevents programs from abruptly stopping by:

  • Isolating Errors: Code prone to errors is isolated within try blocks, ensuring the rest of the program is unaffected.
  • Providing Recovery Paths: The catch block offers a way to handle errors, recover gracefully, or provide alternative logic.
  • Cleanup with finally: Resources like file handles or network connections are properly closed, preventing resource leaks.

Also Read: File Handling in Java: How to Work with Java Files?

Do you also wish to write codes like this fluently? Because Python is an easy language to learn, you can headstart your journey with upGrad’s basic Python programming course and explore further!

While Java’s built-in exceptions cover many standard error scenarios, some applications require custom error messages or specific behavior.

This is where custom exceptions come in. Let’s dive into it!

Designing and Implementing Custom Exceptions in Java

A custom exception allows you to create meaningful, application-specific error handling. For example, if you’re building a banking application, you might want to create exceptions like InsufficientFundsException or AccountNotFoundException to represent domain-specific errors.

Custom exceptions are useful when:

  • The built-in exceptions don’t clearly convey the problem in your application’s context.
  • You must add extra information or logic to the error, such as user-friendly messages or custom behavior.
  • You want to improve code readability and make debugging easier.

Now, let’s see how to create the custom exception step-by-step:

Step 1. Decide the Type of Custom Exception:

  • Extend the Exception class if you want your exception to be a checked exception (requires explicit handling).
  • Extend the RuntimeException class if you want it to be an unchecked exception (it can occur without explicit handling).

Step 2. Define the Exception Class:

Add constructors to initialize the exception with custom messages or additional data.

Step 3. Throw and Handle the Custom Exception:

  • Use the throw keyword to raise the exception.
  • Use try-catch blocks or throws declarations to handle it appropriately.

Code Example: Creating a Custom Exception

Now that you have got the theoretical steps, let’s see the complete process implementation with code examples to help you understand better.

1. Define the Custom Exception Class

// Defining a custom exception
class InsufficientFundsException extends Exception {
    // Constructor with a custom message
    public InsufficientFundsException(String message) {
        super(message);  // Pass the message to the Exception class
    }
}

2. Use the Custom Exception

public class CustomExceptionExample {
    // Method to simulate withdrawing money
    public static void withdraw(double amount, double balance) throws InsufficientFundsException {
        if (amount > balance) {
            // Throw the custom exception if funds are insufficient
            throw new InsufficientFundsException("Insufficient funds: Unable to withdraw " + amount);
        }
        System.out.println("Withdrawal successful! Remaining balance: " + (balance - amount));
    }

    public static void main(String[] args) {
        double balance = 500.0;  // Initial account balance

        try {
            withdraw(600.0, balance);  // Attempt to withdraw more than the balance
        } catch (InsufficientFundsException e) {
            // Handle the custom exception
            System.out.println("Error: " + e.getMessage());
        }
    }
}

Output:

Error: Insufficient funds: Unable to withdraw 600.0

In the above code snippet:

  • A constructor is provided to accept a custom error message, which is passed to the parent Exception class.
  • The withdraw method checks if the withdrawal amount exceeds the balance. If true, it throws the InsufficientFundsException.
  • In the main method, a try-catch block handles the exception.

 

Wish to build your foundational knowledge of Java? Start with upGrad’s core Java basics course and explore further!

 

Also Read: How to Code, Compile, and Run Java Projects

Exceptions are an integral part of programming, and as a Java developer, you’ll encounter various of them. Let’s understand them!

Identifying and Understanding Common Java Exceptions

Understanding the most common exceptions and their causes is essential for debugging effectively and writing error-resilient code. 

Let’s explore some of the frequently encountered exceptions in Java, their causes, and how they occur in everyday coding.

1. NullPointerException: Accessing Null References

This exception occurs when you attempt to access or modify an object that has not been initialized (i.e., is null).

How It Happens:

  • Calling a method on a null object.
  • Accessing a null object’s properties.

Code Example:

public class NullPointerExample {
    public static void main(String[] args) {
        String text = null;  // Uninitialized string
        System.out.println(text.length());  // Triggers NullPointerException
    }
}

Output:

Exception in thread "main" java.lang.NullPointerException

How to Avoid: Always check for null before accessing objects, as shown in the below code:

if (text != null) {
    System.out.println(text.length());
}

2. IOException: Input/Output Operation Failures

If something goes wrong, this exception is thrown during I/O operations, such as reading from or writing to a file.

How It Happens:

  • File not found.
  • Insufficient permissions to access the file.

Code Example:

import java.io.FileReader;
import java.io.IOException;

public class IOExceptionExample {
    public static void main(String[] args) {
        try {
            FileReader file = new FileReader("nonexistentfile.txt");  // File not found
        } catch (IOException e) {
            System.out.println("Error: " + e.getMessage());
        }
    }
}

Output:

Error: nonexistentfile.txt (No such file or directory)

How to Avoid:

  • Verify file paths and permissions before performing file operations.
  • Use exception handling (try-catch) to handle potential errors gracefully.

3. ArithmeticException: Invalid Arithmetic Operations

This exception is triggered by invalid arithmetic operations, such as dividing a number by zero.

How It Happens:

  • Performing a division by zero.
  • Using invalid mathematical expressions.

Code Example:

public class ArithmeticExample {
    public static void main(String[] args) {
        int result = 10 / 0;  // Division by zero
        System.out.println("Result: " + result);
    }
}

Output:

Exception in thread "main" java.lang.ArithmeticException: / by zero

How to Avoid: Check denominators before performing division. See how it’s done below:

if (denominator != 0) {
    System.out.println(10 / denominator);
} else {
    System.out.println("Cannot divide by zero.");
}

Understanding these exceptions is the first step toward mastering exception handling in Java with examples!

Also Read: Top 32 Exception Handling Interview Questions and Answers [For Freshers & Experienced]

Next, let’s get into some advanced techniques for exception handling in Java with examples!

upGrad’s Exclusive Software Development Webinar for you –

SAAS Business – What is So Different?

 

 

 

Advanced Techniques for Exception Handling in Java

Exception handling in Java goes beyond basic try-catch blocks. Advanced techniques enable developers to write cleaner, more efficient, context-aware, error-handling code.

Let’s explore these advanced concepts of exception handling in Java with examples.

1. Exception Propagation

Exception propagation is a mechanism in Java where an exception raised in one method moves up the call stack until a try-catch block catches it or terminates the program if unhandled.

When an exception occurs:

  • The method where it’s thrown doesn’t handle it.
  • It is passed (propagated) to the method that called it.
  • This continues up the stack until it’s caught or the program terminates.

Have a look at the code example below:

public class ExceptionPropagationExample {
    // Method that throws an exception
    public static void methodA() {
        throw new ArithmeticException("Division by zero in methodA");
    }

    // Method that calls methodA
    public static void methodB() {
        methodA();  // Exception propagates to methodB
    }

    public static void main(String[] args) {
        try {
            methodB();  // Exception propagates to main
        } catch (ArithmeticException e) {
            System.out.println("Caught Exception: " + e.getMessage());
        }
    }
}

Output:

Caught Exception: Division by zero in methodA

Code Explanation:

  • methodA: Throws an ArithmeticException.
  • methodB: Does not handle the exception, so it propagates to main().
  • main(): Catches the exception and prints the message.

This shows how exceptions travel up the call stack, allowing centralized error handling.

2. Chained Exceptions

Sometimes, one exception causes another. Chaining exceptions lets you link these related errors, preserving the full context for debugging

This is particularly useful when you want to:

  • Preserve the original exception.
  • Add additional context to the error message.

Have a look at the code example below:

public class ChainedExceptionExample {
    public static void main(String[] args) {
        try {
            methodA();
        } catch (Exception e) {
            System.out.println("Caught Exception: " + e.getMessage());
            System.out.println("Caused by: " + e.getCause());
        }
    }

    // Method that simulates an error and chains it
    public static void methodA() throws Exception {
        try {
            int result = 10 / 0;  // Triggers ArithmeticException
        } catch (ArithmeticException e) {
            throw new Exception("Error in methodA", e);  // Chaining exception
        }
    }
}

Output:

Caught Exception: Error in methodA  
Caused by: java.lang.ArithmeticException: / by zero

Code Explanation:

  • The ArithmeticException is caught in methodA and wrapped in a new Exception using chaining.
  • In main(), both the original and chained exceptions are accessible for debugging, preserving the context.

3. Using try-with-resources (Java 7 and Above)

Managing resources like file streams or database connections can be tricky. If not closed properly, they can lead to resource leaks. 

The try-with-resources statement, introduced in Java 7, automates resource management by automatically closing resources when no longer needed.

Have a look at the code example below:

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class TryWithResourcesExample {
    public static void main(String[] args) {
        // Using try-with-resources for automatic resource management
        try (BufferedReader reader = new BufferedReader(new FileReader("example.txt"))) {
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);  // Print file content
            }
        } catch (IOException e) {
            System.out.println("Error reading the file: " + e.getMessage());
        }
    }
}

Output (if file exists):

File content line 1  
File content line 2  
...

Output (if file doesn’t exist):

Error reading the file: example.txt (No such file or directory)

Code Explanation:

  • Automatic Resource Management: The BufferedReader resource is automatically closed after the try block, even if an exception occurs.
  • Simplified Code: No need for explicit finally blocks to close resources manually.

There you go! You must practice these concepts to take your exception handling in Java skills to the next level!

Also Read: Top 10 Java Books to Read to Improve Your Knowledge

Best Practices for Robust Exception Handling in Java

Exception handling in Java is not just about catching errors; it’s about doing so in a way that ensures your application remains reliable, maintainable, and efficient. Following best practices helps you write clean and predictable code that is easier to debug.

Let’s explore key practices to make your exception handling robust and effective.

1. Catch Specific Exceptions

Always catch specific exceptions instead of using generic ones like Exception or Throwable. Specific handlers make debugging easier and provide clearer error messages.

Understand it with the code snippet below:

try {
    int result = 10 / 0;
} catch (ArithmeticException e) {
    System.out.println("Arithmetic Error: Division by zero.");
}

2. Log Exceptions with Meaningful Messages

Use proper logging frameworks (e.g., Log4j, SLF4J) to log exceptions. Include meaningful messages and stack traces to provide a clear context for debugging.

See how it should be implemented:

import java.util.logging.Logger;

public class LoggingExample {
    private static final Logger logger = Logger.getLogger(LoggingExample.class.getName());

    public static void main(String[] args) {
        try {
            int result = 10 / 0;
        } catch (ArithmeticException e) {
            logger.severe("Arithmetic error occurred: " + e.getMessage());
        }
    }
}

3. Avoid Using Exceptions for Control Flow

Exceptions are expensive in performance and should not replace regular conditional checks. Use proper logic to handle predictable conditions instead of relying on exceptions.

Example (What NOT to Do):

try {
    int[] numbers = {1, 2, 3};
    System.out.println(numbers[5]);  // Avoid triggering exceptions deliberately
} catch (ArrayIndexOutOfBoundsException e) {
    System.out.println("Index out of bounds!");  // Poor control flow
}

Better Approach:

int[] numbers = {1, 2, 3};
if (5 < numbers.length) {
    System.out.println(numbers[5]);
} else {
    System.out.println("Index out of bounds!");
}

4. Use try-with-resources for Efficient Resource Management

Always use try-with-resources to manage resources like file streams and database connections. It ensures resources are closed automatically, even in the event of an exception.

Here’s how to do it:

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class TryWithResourcesBestPractice {
    public static void main(String[] args) {
        try (BufferedReader reader = new BufferedReader(new FileReader("example.txt"))) {
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            System.out.println("Error reading file: " + e.getMessage());
        }
    }
}

Adopting these best practices will make your applications more resilient and maintainable, helping you become a better Java developer.

Also Read: Java Developer Salary: What to Expect in India 2025

How can upGrad Help You Advance Your Java Skills?

Do you want to level up your Java skills and confidently tackle real-world programming challenges? Mastering core concepts like exception handling in Java is a game-changer for developers aiming to build robust, error-free applications.

upGrad specializes in bridging the gap between learning and career advancement. Their Java programs are tailored to equip you with foundational and advanced skills, ensuring you’re ready to tackle industry challenges head-on. 

Some of the top courses include:

 

Take the first step today: book a career counseling session with upGrad experts, upskill, and excel in your future ahead!

 

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.cogentinfo.com/resources/java-developer-demographics-and-statistics-in-the-us

Frequently Asked Questions

1. What is exception handling in Java?

2. Why is exception handling important in Java?

3. What are checked and unchecked exceptions?

4. What is exception propagation?

5. What is the purpose of custom exceptions in Java?

6. How does try-with-resources work?

7. What is a NullPointerException?

8. What is exception chaining?

9. Why should exceptions not be used for control flow?

10. How can exceptions be logged effectively?

11. How can upGrad help me learn Java exception handling?

Sriram

171 articles published

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

View Program
upGrad

Microsoft | upGrad KnowledgeHut

Microsoft Azure Data Engineering Certification

Access Digital Learning Library

Certification

45 Hrs Live Expert-Led Training

View Program
upGrad

upGrad KnowledgeHut

Professional Certificate Program in UI/UX Design & Design Thinking

#1 Course for UI/UX Designers

Bootcamp

3 Months

View Program