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.
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 thetry
block.catch
block: If an exception of a specific type occurs in thetry
block, the correspondingcatch
block is executed. There can be multiplecatch
blocks to handle different types of exceptions.finally
block: The code inside thefinally
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.
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.
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, includingFileNotFoundException
. 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 tonull
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.
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.
// 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.
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.
// 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());
}
}
}
Compile:
javac CommandLineValidator.java
Run with valid arguments:
java CommandLineValidator 30 1
Run to trigger
InvalidAgeException
:java CommandLineValidator 150 1
Run to trigger
ArrayOutOfBoundException
:java CommandLineValidator 30 5