Exception Handling in Java

Introduction

Exception handling is a powerful mechanism in Java that allows developers to manage runtime errors, ensuring the normal flow of the application. In this blog, we will explore the different types of exceptions, the use of try-catch blocks, and how to create custom exceptions.

Types of Exceptions

In Java, exceptions are categorized into three main types:

Checked Exceptions

Checked exceptions are exceptions that are checked at compile time. If a method can throw a checked exception, it must either handle the exception using a try-catch block or declare it using the throws keyword. Examples of checked exceptions include IOException, SQLException, and ClassNotFoundException.

import java.io.*;

public class CheckedExceptionExample {
    public static void main(String[] args) {
        try {
            FileReader file = new FileReader("nonexistentfile.txt");
        } catch (FileNotFoundException e) {
            System.out.println("File not found.");
        }
    }
}

Unchecked Exceptions

Unchecked exceptions are exceptions that are not checked at compile time. They include subclasses of RuntimeException and are usually caused by programming errors, such as logical errors or improper use of APIs. Examples of unchecked exceptions include NullPointerException, ArrayIndexOutOfBoundsException, and ArithmeticException.

public class UncheckedExceptionExample {
    public static void main(String[] args) {
        int[] array = new int[5];
        System.out.println(array[10]); // This will throw ArrayIndexOutOfBoundsException
    }
}

Errors

Errors are serious problems that a reasonable application should not try to catch. They are usually caused by the environment in which the application is running. Examples of errors include OutOfMemoryError and StackOverflowError.

public class ErrorExample {
    public static void main(String[] args) {
        main(args); // This will throw StackOverflowError
    }
}

Try-Catch Blocks

The try-catch block is used to handle exceptions. The code that might throw an exception is placed inside the try block, and the code to handle the exception is placed inside the catch block.

public class TryCatchExample {
    public static void main(String[] args) {
        try {
            int divideByZero = 5 / 0;
        } catch (ArithmeticException e) {
            System.out.println("ArithmeticException: Division by zero.");
        }
    }
}

Finally Block

The finally block is used to execute important code, such as closing resources, whether an exception is thrown or not. It follows the try-catch block.

public class FinallyExample {
    public static void main(String[] args) {
        try {
            int divideByZero = 5 / 0;
        } catch (ArithmeticException e) {
            System.out.println("ArithmeticException: Division by zero.");
        } finally {
            System.out.println("Finally block is always executed.");
        }
    }
}

Try-With-Resources

The try-with-resources statement ensures that each resource is closed at the end of the statement. It is used with classes that implement the AutoCloseable interface.

import java.io.*;

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

Creating Custom Exceptions

In Java, you can create your own exceptions by extending the Exception class for checked exceptions or the RuntimeException class for unchecked exceptions.

Custom Checked Exception

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

public class CustomCheckedExceptionExample {
    public static void main(String[] args) {
        try {
            throw new CustomCheckedException("This is a custom checked exception.");
        } catch (CustomCheckedException e) {
            System.out.println(e.getMessage());
        }
    }
}

Custom Unchecked Exception

class CustomUncheckedException extends RuntimeException {
    public CustomUncheckedException(String message) {
        super(message);
    }
}

public class CustomUncheckedExceptionExample {
    public static void main(String[] args) {
        throw new CustomUncheckedException("This is a custom unchecked exception.");
    }
}

Conclusion

Exception handling in Java is essential for creating robust and error-free applications. Understanding the different types of exceptions, using try-catch blocks effectively, and creating custom exceptions are key skills for any Java developer. Proper exception handling ensures that your application can handle unexpected situations gracefully and maintain a smooth user experience.