Skip to content

Exceptions

An exception is an event that disrupts the normal flow of a program's instructions at runtime. It's essentially a runtime error. When an error occurs, Java creates an exception object and "throws" it. Instead of letting the program crash, these exceptions can be intercepted and execute special code to handle the problem gracefully.

Example : by displaying a user-friendly error message, logging the error, or retrying the operation.

The purpose of exception handling is to provide a structured way to catch and manage these errors.

The General Form of an Exception-Handling Block

The basic structure for handling exceptions in Java involves the try, catch, and optional finally blocks.

java
try {
    // Code that might throw an exception
} catch (ExceptionType1 e1) {
    // Code to handle ExceptionType1
} catch (ExceptionType2 e2) {
    // Code to handle ExceptionType2
} finally {
    // Code that will always execute, regardless of an exception
}
  • try block: Code that might cause an exception is placed inside the try block.

  • catch block: If an exception of a specific type occurs in the try block, the corresponding catch block is executed. There can be multiple catch blocks to handle different types of exceptions.

  • finally block: The code inside the finally block is always executed, whether an exception occurred or not. It's typically used for cleanup operations, like closing files or network connections.

  • throw: Manually throws an exception. It's used to signal that an error condition has occurred.

  • throws: Declares that a method might throw one or more exceptions. It's part of the method signature and warns other code that calls this method to handle the potential exceptions.

java
public class KeywordDemo {
	
    public static void checkAge(int age) throws IllegalArgumentException 
    {
        if (age < 18) {
            // 'throw' is used to create and throw a new exception.
            throw new IllegalArgumentException("Access denied - You must be at least 18 years old.");
        } else {
            System.out.println("Access granted - You are old enough!");
        }
    }

    public static void main(String[] args) {
        try {
            checkAge(20); // runs without an exception.
            
			checkAge(15); // throws an exception.   
        }
        catch (IllegalArgumentException e) {
            System.out.println("Caught an exception: " 
	            + e.getMessage());
        } 
        finally {
            System.out.println("The 'finally' block is always executed.");
        }
    }
}

Output:

Access granted - You are old enough!

Caught an exception: Access denied - You must be at least 18 years old.

The 'finally' block is always executed.

Multiple catch Blocks and Nested try Blocks

You can use multiple catch blocks after a single try block to handle different types of exceptions. The JVM will execute the first catch block that matches the type of the exception thrown.

A try block can be nested inside another try block. If an exception occurs in the inner try block and is not caught by an inner catch block, it is passed to the outer catch blocks for handling.

java
public class AdvancedHandlingDemo {
    public static void main(String[] args) {
        try {
            // --- Outer try block ---
            int[] numbers = {4, 8, 16, 32, 64};
            int[] denominators = {2, 0, 4, 4};

            for (int i = 0; i < numbers.length; i++) {
                try {   // --- Inner try block ---
                    System.out.println(numbers[i] 
	                    + " / " + denominators[i] 
	                    + " is " 
	                    + numbers[i] / denominators[i]);
                } 
                catch (ArithmeticException e) {
                    System.out.println("Can't divide by zero!");
                }
            }
        } 
        catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("Array index out-of-bounds: No matching element in denominators array.");
        } 
        // Outer catch for any other potential errors
        catch (Exception e) {
            System.out.println("A general error occurred: "
		        + e.getMessage());
        }

        System.out.println("Program finished.");
    }
}

Output:

4 / 2 is 2
Can't divide by zero!
16 / 4 is 4
32 / 4 is 8
Array index out-of-bounds: No matching element in denominators array.
Program finished.

Exception Types

The main difference between checked and unchecked exceptions is how the compiler treats them.

Checked Exceptions:

These are exceptions that the Java compiler throws at compile-time and should be handled before being able to compile the program. They typically represent predictable errors that can occur in a valid program, like a file not being found.

If a method can throw a checked exception, it must either be handled with a try-catch block or declared with the throws keyword.

  • FileNotFoundException: Thrown when an attempt to open the file denoted by a specified pathname has failed.

  • IOException: A general I/O (Input/Output) exception. It's a superclass for many more specific I/O exceptions, including FileNotFoundException. It's thrown when an I/O operation fails or is interrupted.

ClassNotFoundException, IllegalAccessException, InterruptedException

Unchecked (Runtime) Exceptions:

Runtime errors or Unchecked Exceptions usually represent programming errors or logic flaws, such as trying to access a null object or an invalid array index which are thrown during runtime. The compiler does not require them to be handled for compiling the program.

  • ArithmeticException: Thrown for an exceptional arithmetic condition, most commonly dividing an integer by zero.

  • ArrayIndexOutOfBoundsException: Thrown when trying to access an array element with an invalid index (either negative or greater than or equal to the array's size).

  • NullPointerException: Thrown when trying to use a reference variable that points to null as if it were referencing an actual object (e.g., calling a method on it).

IllegalArgumentException, IndexOutOfBoundsException, NegativeArraySizeException, NumberFormatException

Custom (User-Defined) Exceptions

Java provides many built-in exceptions, they are often too general. Custom exception can be created to handle error conditions that are specific to an application's logic or business rules.

A custom exception makes the code more readable and allows for handling specific errors with more precision.

To create a custom exception, Exception class is extended (for a checked exception) or the RuntimeException class is extended (for an unchecked exception).


Creating a custom exception for an invalid age.

java
class InvalidAgeException extends Exception {
    
    public InvalidAgeException(String message) {
        super(message);
    }
}

public class CustomExceptionDemo {
    
    public static void validate(int age) throws InvalidAgeException 
	{
        if (age < 18) {
            throw new InvalidAgeException("User must be at least 18 years old.");
        }
        System.out.println("User age is valid.");
    }
    
    public static void main(String[] args) {
		try {
			validate(15);
		} catch (InvalidAgeException e) {
			System.err.println("Validation Error: " 
				+ e.getMessage());
		}
    }
}

Practical Application

Banking Application with Custom Exception

This program simulates a bank account, throwing a custom InsufficientFundsException if a withdrawal would result in a negative balance.

java
// Custom exception for banking errors
class InsufficientFundsException extends Exception {
    public InsufficientFundsException(String message) {
        super(message);
    }
}


class BankAccount {
    private double balance;

    public BankAccount(double initialBalance) {
        this.balance = initialBalance;
    }

    public void deposit(double amount) {
        balance += amount;
        System.out.println("Deposited: " + amount);
    }

    public void withdraw(double amount) throws InsufficientFundsException 
    {
        if (amount > balance) {
            throw new InsufficientFundsException("Withdrawal amount exceeds current balance.");
        }
        balance -= amount;
        System.out.println("Withdrew: " + amount);
    }

    public double getBalance() {
        return balance;
    }
}

public class BankingApp {
    public static void main(String[] args) {
        BankAccount account = new BankAccount(1000.00);
        
        // --- Transaction 1: Successful Withdrawal ---
        System.out.println("--- Attempting to withdraw 200.00 ---");
        try {
            account.withdraw(200.00);
        } catch (InsufficientFundsException e) {
            System.err.println("Error: " + e.getMessage());
        } finally {
            System.out.printf("Current balance is: %.2f\n\n",
				account.getBalance());
        }
        
        // --- Transaction 2: Failed Withdrawal ---
        System.out.println("--- Attempting to withdraw 900.00 ---");
        try {
            account.withdraw(900.00);
        } catch (InsufficientFundsException e) {
            System.err.println("Error: " + e.getMessage());
        } finally {
            System.out.printf("Current balance is: %.2f\n",
				account.getBalance());
        }
    }
}

Custom Exception for Number Input

Takes an integer from the user and throws a custom exception if the number is greater than 20.

java
import java.util.Scanner;

// Custom exception for number validation
class NumberTooLargeException extends Exception {
    public NumberTooLargeException(String message) {
        super(message);
    }
}

public class NumberValidator {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.print("Enter an integer (must not be greater than 20): ");

        try {
            int number = scanner.nextInt();
            if (number > 20) {
                throw new NumberTooLargeException("The number "
	                 + number + " is too large!");
            }
            System.out.println("You entered: " + number 
	            + ". The number is valid.");
        } catch (NumberTooLargeException e) {
            System.err.println("Error: " + e.getMessage());
        } catch (Exception e) {
            System.err.println("Invalid input. Please enter an integer.");
        } finally {
            scanner.close();
        }
    }
}

Custom Exceptions for Command-Line Arguments

Custom exceptions named InvalidAgeException and ArrayOutOfBoundException and handles them based on command-line input.

java
// Custom exceptions
class InvalidAgeException extends Exception {
    public InvalidAgeException(String message) {
	     super(message); 
	}
}

class ArrayOutOfBoundException extends Exception {
    public ArrayOutOfBoundException(String message) { 
	    super(message); 
	}
}

public class CommandLineValidator {
    public static void main(String[] args) {
        try {
            if (args.length < 2) {
                throw new IllegalArgumentException("Usage: java CommandLineValidator <age> <index>");
            }

            // --- Validate Age (first argument) ---
            int age = Integer.parseInt(args[0]);
            if (age < 0 || age > 120) {
                throw new InvalidAgeException("Age must be between 0 and 120.");
            }
            System.out.println("Age validation successful: " + age);

            // --- Validate Array Index (second argument) ---
            int[] data = {10, 20, 30};
            int index = Integer.parseInt(args[1]);
            if (index < 0 || index >= data.length) {
                throw new ArrayOutOfBoundException("Index "
		            + index + " is out of bounds for the array.");
            }
            System.out.println("Array access successful at index " 
	            + index + ": value is " + data[index]);

        } 
        catch (InvalidAgeException | ArrayOutOfBoundException e) 
        {
            System.err.println("Validation Error: " + e.getMessage());
        } 
        catch (NumberFormatException e) 
        {
            // Catch error if arguments are not integers
            System.err.println("Input Error: Please provide valid integer arguments.");
        } 
        catch (IllegalArgumentException e) 
        {
            // Catch error for wrong number of arguments
            System.err.println("Usage Error: " + e.getMessage());
        }
    }
}
  1. Compile: javac CommandLineValidator.java

  2. Run with valid arguments: java CommandLineValidator 30 1

  3. Run to trigger InvalidAgeException: java CommandLineValidator 150 1

  4. Run to trigger ArrayOutOfBoundException: java CommandLineValidator 30 5

Made with ❤️ for students, by a fellow learner.