Before learning about Java Exception Types. Let us first understand what exactly an exception is.
What Is an Exception In Java?
Imagine you’re a student preparing for an important exam. But on the exam day, you fall sick and can’t make it. In Java, exceptions are like unexpected disruptions that disrupt the normal flow of your program. They can occur due to bad input, unavailable resources, or unexpected errors. Just as you need a backup plan when things go wrong, handling exceptions in Java allows your program to respond to problems gracefully.
Now to handle the exception, we must know what type of exception.
Types Of Java Exception
Exceptions in Java can be categorized into two ways i.e.
- Built-In Exceptions.
- Checked Exceptions.
- Unchecked Exceptions.
- Customized Exceptions.
Built-In Exceptions
Built-in exceptions, also known as standard exceptions, are predefined exception classes provided by Java. These exceptions cover a wide range of common errors and exceptional situations that can occur during program execution. Built-in exceptions are part of the Java standard library and provide a standardized way to handle common exceptional scenarios.
Built-In Exceptions can be further classified into two categories –
- Checked Exceptions
- Unchecked Exceptions
Checked Exceptions
Checked exceptions are exceptions that the Java compiler requires you to handle explicitly in your code. These exceptions are checked at compile-time, and if not handled properly, the code will not compile. Checked exceptions are subclasses of the Exception class but not subclasses of the RuntimeException class.
Here are some key points about checked exceptions:
- The Java compiler ensures that all checked exceptions are either caught or declared to be thrown.
- Checked exceptions are used for scenarios where it’s possible to recover from the exception, and the programmer is forced to handle the exception explicitly.
- Some examples of checked exceptions in Java include IOException, SQLException, and ClassNotFoundException.
Example 1: FileNotFoundException Exception
In Java, the `FileNotFoundException` is a type of exception that occurs when a file is requested but cannot be found or accessed. It is a subclass of the `IOException` class and is commonly encountered when working with file operations.
Code:
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class FileReadExample {
public static void main(String[] args) {
try {
File file = new File("example.txt");
Scanner scanner = new Scanner(file);
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
System.out.println(line);
}
scanner.close();
} catch (FileNotFoundException e) {
System.out.println("File not found: " + e.getMessage());
}
}
}
Output:
File not found: example.txt (No such file or directory)
In this example, we’re attempting to read the contents of a file named `example.txt`. However, if the file does not exist in the specified location, a `FileNotFoundException` will be thrown. The code uses a `try-catch` block to handle this exception.
Example 2: ClassNotFound Exception
In Java, the `ClassNotFoundException` is a type of exception that occurs when a class is not found at runtime. It typically happens when the Java Virtual Machine (JVM) tries to load a class dynamically using methods like `Class.forName()` or `ClassLoader.loadClass()`, but the specified class cannot be found in the classpath.
Code:
public class ClassNotFoundExample {
public static void main(String[] args) {
try {
Class clazz = Class.forName("com.example.NonExistentClass");
} catch (ClassNotFoundException e) {
System.out.println("Class not found: " + e.getMessage());
}
}
}
Output:
Class not found: com.example.NonExistentClass
In this example, we’re trying to load a class named `com.example.NonExistentClass` dynamically using the `Class.forName()` method. However, if the specified class does not exist in the classpath, a `ClassNotFoundException` will be thrown. The code uses a try-catch block to handle this exception.
Example 3: IllegalAcess Exception
In Java, the `IllegalAccessException` is a type of exception that occurs when a program tries to access a field, method, or constructor of a class that is not accessible due to access modifiers such as `private`, `protected`, or `package-private`.
Code:
public class IllegalAccessExample {
private int privateField;
public static void main(String[] args) {
IllegalAccessExample example = new IllegalAccessExample();
try {
Class clazz = example.getClass();
java.lang.reflect.Field field = clazz.getDeclaredField("privateField");
field.setAccessible(true);
int value = (int) field.get(example);
System.out.println("Private field value: " + value);
} catch (NoSuchFieldException | IllegalAccessException e) {
System.out.println("Illegal access: " + e.getMessage());
}
}
}
Output:
Illegal access: Attempted to access a private field
In this example, we have a class `IllegalAccessExample` with a `private` field named `privateField`. We try to access this private field using Java Reflection by setting its accessibility to true using `field.setAccessible(true)`. However, if the access modifier of the field prevents its access, an `IllegalAccessException` will be thrown.
Unchecked Exceptions
Unchecked exceptions, also known as runtime exceptions, are exceptions that do not need to be explicitly handled in the code. These exceptions are subclasses of the RuntimeException class or its subclasses. Unlike checked exceptions, unchecked exceptions are not required to be declared or caught explicitly.
Here are some key points about unchecked exceptions:
- Unchecked exceptions are checked at runtime rather than at compile time.
- Unchecked exceptions are typically used for scenarios that are not recoverable or unexpected, such as NullPointerException or ArrayIndexOutOfBoundsException.
- Some examples of unchecked exceptions in Java include NullPointerException, ArrayIndexOutOfBoundsException, and IllegalArgumentException.
Example 1: Arithmetic Exception
In Java, the `ArithmeticException` is a type of exception that is thrown when an arithmetic operation encounters an error or an exceptional condition. It typically occurs when performing arithmetic operations such as division by `zero` or an `overflow/underflow `condition.
Code:
public class ArithmeticExceptionExample {
public static void main(String[] args) {
int dividend = 10;
int divisor = 0;
try {
int result = dividend/divisor;
System.out.println("Result: " + result);
} catch (ArithmeticException e) {
System.out.println("Error: " + e.getMessage());
}
}
}
Output:
Error: / by zero
In this example, we have an arithmetic operation where we attempt to divide `dividend` by `divisor`. However, the value of the divisor is set to zero, which results in an arithmetic error. The division by zero operation throws an `ArithmeticException`.
Example 2: ArrayIndexOutOfIndex Exception
In Java, the `ArrayIndexOutOfBoundsException` is a type of exception that is thrown when attempting to access an array element in array of Java using an invalid index. It occurs when the index used to access an array is either negative or greater than or equal to the length of the array.
Code:
public class ArrayIndexOutOfBoundsExceptionExample {
public static void main(String[] args) {
int[] numbers = {1, 2, 3};
try {
int element = numbers[3];
System.out.println("Element: " + element);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Error: " + e.getMessage());
}
}
}
Output:
Error: Index 3 out of bounds for length 3
In this example, we have an array of numbers with three elements. However, we attempt to access the element at index 3, which is outside the valid index range of the array. This leads to an `ArrayIndexOutOfBoundsException` being thrown.
Example 3: NullPointer Exception
In Java, the `NullPointerException` is a type of exception that is thrown when trying to access or perform operations on a null object reference. It occurs when an object reference variable doesn’t point to any valid object in memory but is used as if it does.
Code:
public class NullPointerExceptionExample {
public static void main(String[] args) {
String name = null;
try {
int length = name.length();
System.out.println("Length: " + length);
} catch (NullPointerException e) {
System.out.println("Error: " + e.getMessage());
}
}
}
Output:
Error: Cannot invoke "String.length()" because "name" is null
In this example, we have a `String` variable name initialized with a null value. We then try to access the `length()` method on this null reference, which leads to a `NullPointerException` being thrown.
Checked and Unchecked Exceptions are not limited to the above examples. These are just a few examples of checked and unchecked exceptions. You can refer to another blog to know more in detail.
Difference Between Checked Vs Unchecked Exception
Checked Exceptions | Unchecked Exceptions |
Must be declared in the method signature or handled using try-catch blocks or throws clause. | Do not require explicit declaration or handling mechanisms. |
Checked exceptions pertain to conditions that are expected to occur and can be handled gracefully. | Unchecked exceptions are typically caused by programming errors or exceptional situations. |
The compiler enforces the handling or declaration of checked exceptions by requiring try-catch blocks or the throws clause. | The compiler does not enforce the handling of the declaration of unchecked exceptions. |
Checked exceptions are part of the Java checked exception hierarchy. | Unchecked exceptions do not follow the checked exception hierarchy. |
Checked exceptions must be explicitly caught or declared in the method signature. | Unchecked exceptions are not required to be explicitly caught or declared. |
Examples of Checked exceptions:FileNotFound ExceptionNoSuchField ExceptionInterrupted ExceptionNoSuchMethod ExceptionClassNotFound ExceptionIO Exception | Examples of Unchecked Exceptions:NullPointer ExceptionNumberFormat ExceptionIllegalState ExceptionArrayIndexOutOfBounds ExceptionSecurity ExceptionArithmetic Exception |
User-defined Exceptions
In addition to the built-in exceptions, Java allows you to define your own custom exceptions. User-defined exceptions are created by extending the base Exception class or its subclasses. By creating customized exceptions, you can handle application-specific exceptional conditions that are not covered by the built-in exceptions. They are handled using keywords like try, catch, finally, throw, and throws.
- `try`: A group of statements that could throw an exception are contained within the try block. It is followed by a finally block or a few catch blocks.
Example:
try {
// Code that might throw an exception
}
- `catch`: The catch block is used to catch and handle specific exceptions that occur within the corresponding try block. It contains the code that executes when a particular exception is thrown.
Example:
try {
// Code that might throw an exception
} catch (Exception e) {
// Exception handling code
}
- `finally`: A block of code that always runs, regardless of whether an exception is thrown or not, is defined by the finally block. It is typically used to perform cleanup operations or release resources.
Example:
try {
// Code that might throw an exception
} catch (Exception e) {
// Exception handling code
} finally {
// Code that always executes, regardless of whether an exception occurs or not
}
- `throw`: The throw keyword is used to explicitly throw an exception. It is followed by an instance of the Throwable class or one of its subclasses. This allows developers to manually trigger exceptions based on certain conditions.
Example:
public void processAge(int age) {
if (age < 0) {
throw new IllegalArgumentException("Age cannot be negative");
}
// Process age further
}
- `throws`: The throws keyword is used in method signatures to declare that the method might throw one or more exceptions. It specifies the type of exceptions that the method can throw, allowing callers to handle those exceptions.
Example:
public void readFile(String fileName) throws IOException {
// Code that reads a file
}
Let’s see some variations in try-catch block statements.
- Catching Multiple Exceptions:
try {
// Code that might throw exceptions
// ...
} catch (ExceptionType1 e1) {
// Exception handling code for ExceptionType1
// ...
} catch (ExceptionType2 e2) {
// Exception handling code for ExceptionType2
// ...
} catch (ExceptionType3 e3) {
// Exception handling code for ExceptionType3
// ...
} catch (Exception e) {
// Exception handling code for any other exceptions
// ...
}
In this variation, multiple catch blocks are used to catch different types of exceptions. Each catch block handles a specific type of exception, allowing for more fine-grained exception handling.
- Nested Try-Catch Blocks:
try {
// Outer try block
try {
// Inner try block
// Code that might throw an exception
// ...
} catch (Exception e) {
// Exception handling code for the inner try block
// ...
}
} catch (Exception e) {
// Exception handling code for the outer try block
// ...
}
Nested try-catch blocks are used when there is a need to handle exceptions at different levels. The inner try-catch block handles exceptions specific to its scope, and if an exception is not caught, it propagates to the outer catch block for handling.
Difference Between Final, Finally And Finalize
Now you must have heard various Java keywords similar to finally i.e. `final`, and `finalize`. Let’s see some differences between all three:
Keyword | Purpose | Usage |
final | Used to declare a constant or make a variable, method, or class unchangeable. | Variables declared as final cannot be reassigned.Methods declared as final cannot be overridden.Classes declared as final cannot be inherited. |
finally | A block that is always executed after the try-and-catch blocks, regardless of whether an exception occurs or not. | Used to perform cleanup operations or release resources.It ensures that specific code is executed even if an exception is thrown or caught. |
finalize | A method that is called by the garbage collector before reclaiming an object’s memory. | Used for performing final cleanup operations on an object before it is destroyed.Deprecated in Java 9 and no longer recommended for use. |
Difference Between Throw And Throws Keyword
Throw | Throws |
The throw keyword is used to explicitly throw an exception within a method. | The throws keyword is used in the method signature to declare that a method can potentially throw one or more checked exceptions. |
It is used when you want to indicate an exceptional condition manually, such as when an error or unexpected situation occurs. | It is used when a method may encounter exceptions that it cannot handle, and it wants to pass the responsibility of handling those exceptions to its caller. |
To use throw, you need to provide an instance of an exception or an expression that evaluates to an exception. | The throws keyword specifies the types of exceptions that the method can throw, allowing the caller to handle those exceptions appropriately. |
To understand types of exceptions in detail, you can refer to the blog – “Types of Exceptions in Java”.
Custom Exceptions In Java
What if your exception is not covered in the above mentioned exceptions? Don’t worry, in Java, there is a concept called Custom Exceptions in which you can build your own custom exceptions. Custom Exceptions allow developers to define their own exception classes to represent application-specific errors or exceptional conditions. The purpose of custom exceptions is to provide clear and meaningful error messages to the application users or developers, guiding them on how to resolve the issue.
By using custom exceptions, developers can enforce specific rules or requirements in their applications and provide tailored error handling for different scenarios. This improves the user experience by offering precise feedback and guidance when errors occur, helping users to correct their input and proceed with the desired operation.
Example:
public class InsufficientFundsException extends Exception {
public InsufficientFundsException(String message) {
super(message);
}
}
public class BankAccount {
private double balance;
public void withdraw(double amount) throws InsufficientFundsException {
if (amount > balance) {
throw new InsufficientFundsException("Insufficient funds in the account");
}
balance -= amount;
System.out.println("Withdrawal successful. Remaining balance: " + balance);
}
}
public class Main {
public static void main(String[] args) {
BankAccount account = new BankAccount();
account.deposit(1000);
try {
account.withdraw(1500);
} catch (InsufficientFundsException e) {
System.out.println("Exception caught: " + e.getMessage());
}
}
}
Output:
Deposit: $1000
Withdraw: $1500
Error: Insufficient funds. Available balance: $1000
The code demonstrates a custom exception called InsufficientFundsException that is thrown when attempting to withdraw an amount greater than the account balance. The BankAccount class has a withdraw method that throws this exception. In the Main class, we create a BankAccount instance, deposit funds, and then try to withdraw an amount greater than the balance. If the exception is thrown, it is caught in a catch block, and an error message is printed. Otherwise, a success message and the remaining balance are displayed.
Conclusion
- Exceptions in Java are abnormal conditions or errors that occur during the execution of a program.
- There are two types of exceptions: Built-In Exceptions and User-Defined Exceptions.
- Built-In Exceptions in Java include FileNotFound Exception, ClassNotFound Exception, IllegalAccess Exception, CloneNotSupported Exception, Interrupted Exception, Arithmetic Exception, ArrayIndexOutOfBound Exception, NullPointer Exception, IllegalState Exception, and NumberFormat Exception.
- User-Defined Exceptions can be created by extending the existing Exception classes or implementing the Throwable interface.
- Checked Exceptions are checked at compile-time and must be handled using try-catch blocks or declared in the method signature using the throws keyword.
- Unchecked Exceptions are not checked at compile-time and do not require explicit handling.
- The difference between Checked and Unchecked Exceptions lies in their handling requirements and the compiler’s enforcement.
- Important keywords related to exceptions include try, catch, finally, throw, and throws.
- The final, finally, and finalize keywords serve different purposes in Java and are not directly related to exceptions.
- The throw keyword is used to explicitly throw an exception, while the throws keyword is used in method declarations to indicate the possibility of throwing an exception.
- Custom Exceptions can be created to handle specific exceptional scenarios in a program.
Happy handling!