When an exception occurs in Java, it disrupts the normal flow of the program's execution, leading to abnormal termination of the program/application. Therefore, understanding the causes of exceptions and how to handle them in Java is crucial.
Exception in Java
There are various reasons for exceptions in Java, including:
- Invalid user input.
- File not found.
- Network connection lost during communication or JVM running out of memory.
Some exceptions occur due to user errors, some due to programmer errors, and others due to physical data source errors.
Based on this, we have three different types of exceptions. All you need to do is understand the exceptions to know how to handle them in Java.
- Checked exception: These are exceptions that occur at compile time, also known as compile-time exceptions. These compile-time exceptions cannot be easily ignored at compile time, so programmers should pay attention to handling these exceptions.
For example, if you use the FileReader class in a program to read data from a file, if the file specified in the constructor does not exist, a FileNotFoundException will occur, and the compiler will prompt the programmer to handle this exception.
Example:
If you try to compile the program above, you will receive the following exception:
C:\>javac FilenotFound_Demo.java
FilenotFound_Demo.java:8: error: unreported exception FileNotFoundException; must be caught or declared to be thrown
FileReader fr = new FileReader(file);
^
1 error
Note: Since the read() and close() methods of the FileReader class throw IOException, you can observe compiler messages to handle IOException, along with FileNotFoundException.
- Unchecked exception: This is an exception that occurs at runtime, also known as Runtime Exception. This exception includes programming errors, such as logical errors or improper use of APIs. Runtime Exceptions are ignored at compile time.
For example, if you declare an array of 5 elements in a program and try to access the 6th element of the array, the ArrayIndexOutOfBoundsExceptionexception will occur.
Example:
If you compile and execute the program above, you will receive the following exception:
Exception in thread 'main' java.lang.ArrayIndexOutOfBoundsException: 5
at Exceptions.Unchecked_Demo.main(Unchecked_Demo.java:8)
- Error: It differs from exceptions, but it represents issues that exceed the control of the user or programmer. Errors are ignored in the code because there's rarely anything you can do when a program encounters an error. For example, if a buffer overflow error occurs, the error will be thrown. Errors are also ignored at compile time.
Exception Hierarchy in Java
All exception classes are subclasses of the java.lang.Exception class. Exception classes are subclasses of the Throwable class. Another type of exception class is Error, which is also a subclass of the Throwable class.
Errors represent abnormal conditions that should not happen under normal circumstances and are not handled by Java programs. Errors are created to represent errors that occur in the runtime environment. For example, when the JVM runs out of memory. Typically, programs cannot recover from errors.
The exception class has 2 main subclasses: IOException and RuntimeException.
Below is the list of Checked exceptions and Unchecked exceptions available in Java:
Methods in Exception Handling in Java
Below is the table listing important methods available in the Throwable class in Java:
Exception Handling in Java
Catch Block in Exception Handling
The catch block is an exception handler combined with the try and catch keywords. A try/catch block is placed around code that may generate an exception. The code inside the try/catch block is called protected code. Below is the syntax to use the try/catch block:
Syntax
try {
// Enclosed code
} catch (ExceptionName e1) {
// Exception handling block
}
Code prone to exceptions is placed within the try block. When an exception occurs, it is handled by the catch block associated with it. Each try block is immediately followed by a catch block or a finally block.
A catch statement declares the type of exception you are trying to handle. If an exception occurs within the protected code, the catch block following the try block is checked. If the type of exception that occurred is listed in the catch block, the exception is passed to the catch block as a method parameter.
For example:
Below is an array declaration with 2 elements. The code attempts to access the 3rd element of the array, resulting in an exception:
The example above returns the following output:
Exception thrown: java.lang.ArrayIndexOutOfBoundsException: 3
Out of the block
Using multiple catch blocks in Java
A try block can be accompanied by multiple catch blocks.
The syntax for multiple catch blocks is as follows:
try {
// Protected code
} catch (ExceptionType1 e1) {
// Catch block
} catch (ExceptionType2 e2) {
// Catch block
} catch (ExceptionType3 e3) {
// Catch block
}
Các đoạn mã trên biểu thị 3 khối catch, nhưng bạn có thể thêm nhiều khối khác sau try. Nếu ngoại lệ xảy ra trong mã bảo vệ, ngoại lệ sẽ được ném vào khối catch đầu tiên trong danh sách.
Nếu kiểu dữ liệu của ngoại lệ phù hợp với ExceptionType1, nó sẽ được bắt tại đó. Nếu không, ngoại lệ sẽ được chuyển xuống lệnh catch thứ 2 và tiếp tục cho đến khi ngoại lệ được bắt hoặc thất bại qua tất cả các catch. Trong trường hợp này, phương thức hiện tại sẽ ngừng thực thi và ngoại lệ sẽ được ném vào phương thức trước trên call stack.
Ví dụ:
Dưới đây là đoạn mã mô tả cách sử dụng nhiều lệnh try / catch:
Handling Multiple Exceptions with One Catch Block
Starting from Java 7, you can handle multiple exceptions by using a single catch block, making the code simpler.
Below is the basic syntax:
catch (IOException|FileNotFoundException ex) {
logger.log(ex);
throw ex;
Handling Exceptions with Throws/Throw Keywords in Java
If a method does not handle a checked exception, the method must declare it using the throws keyword. The throws keyword appears at the end of the method signature.
You can throw an exception or create a new exception or the exception you just caught using the throw keyword.
There is a difference between the keywords throws and throw. Throws is used to defer the handling of checked exceptions while throw is used to throw an exception.
For example, the method below declares throws RemoteException:
A method can declare throws for multiple exceptions, in which case the exceptions are listed in a comma-separated list.
The method below, for example, declares throws RemoteException and InsufficientFundsException:
Finally Block
The finally block follows a try block or a catch block. The finally block is executed, even if an exception occurs.
Using the finally block allows you to run cleanup-type statements, regardless of what happens in the protected code.
The finally block is placed at the end of the catch block.
Syntax:
try {
// Protected code
} catch (ExceptionType1 e1) {
// Handling the first type of exception
} catch (ExceptionType2 e2) {
// Handling the second type of exception
} catch (ExceptionType3 e3) {
// Handling the third type of exception
}finally {
// The finally block always executes.
}
For example:
In the example above, the output result is:
Exception thrown: java.lang.ArrayIndexOutOfBoundsException: 3
Value of the first element: 6
The finally block is executed
Note:
- The catch clause does not exist without a try statement.
- It is not mandatory to have a finally clause even if a try/catch block is present.
- The try block cannot exist without either a catch or finally clause.
- Code cannot appear in between try, catch, and finally blocks.
Using try-with-resources in Java
When using resources such as streams, connections, etc., we must close these resources using a finally block.
In the example below, the program reads data from a file using FileReader, and this file is closed using a finally block:
try-with-resources, also known as automatic resource management, is a new exception handling mechanism introduced in Java 7, automatically closing the resources used within the try-catch block.
To utilize this command, you only need to declare the necessary resources within the parentheses, and the resource created will automatically be closed after the block ends. Here is the syntax for the try-with-resources statement:
Syntax:
try(FileReader fr = new FileReader('file path')) {
// use the resource
} catch () {
// catch block
}
}
The following example demonstrates a program that reads data from a file using try-with-resources:
Some points to note when using try-with-resources:
- To use a class with try-with-resources, it must implement the AutoCloseable interface, and the close() method is automatically called at runtime.
- You can declare multiple classes in the try-with-resources statement.
- While declaring multiple classes in the try block of the try-with-resources statement, the classes are closed in reverse order.
- Except for declaring resources within parentheses, everything else is similar in the try/catch block of a try statement.
- Resources declared within the try block are implicitly declared last.
Creating User-defined Exception in Java
You can create custom exceptions in Java. However, there are some points to note when writing a custom exception class in Java:
- All exceptions must be subclasses of Throwable.
- If you want to write a checked exception, which is automatically handled by the Handle or Declare Rule, you need to extend the Exception class.
- If you want to write a runtime exception, you need to extend the RuntimeException class.
To define an exception class, you use the following syntax:
class MyException extends Exception {
}
Simply extend the pre-defined exception class to create a custom exception. These exceptions are considered checked exceptions. The InsufficientFundsException class below is a user-defined exception, extending the Exception class.
Exception classes are like any other class, containing fields and useful methods.
Example:
To demonstrate the use of user-defined exceptions, the CheckingAccount class below contains a withdraw() method, throwing an InsufficientFundsException:
The BankDemo program below demonstrates the deposit() and withdraw() methods of CheckingAccount:
Compiling all 3 files above and running BankDemo will return the following output:
Initiating deposit of $500...
Initiating withdrawal of $100...
Attempting withdrawal of $600...
Apologies, insufficient funds by $200.0
Exception: InsufficientFundsException
Occurred at: CheckingAccount.withdraw(CheckingAccount.java:25)
Triggered from: BankDemo.main(BankDemo.java:13)
Common Exceptions
In Java, there are two common types of exceptions:
- JVM Exception: These are exceptions/errors exclusively thrown by the JVM. Examples include NullPointerException, ArrayIndexOutOfBoundsException, ClassCastException.
- Programmatic Exception: These exceptions are explicitly thrown by applications or programming APIs. Examples include IllegalArgumentException, IllegalStateException.
So, in the above Mytour article introducing you to exceptions and exception handling in Java, readers are encouraged to explore further with a basic guide to the Java language to grasp the flexible handling mechanisms in this language. If there are any questions needing clarification, please feel free to leave your comments in the comment section below the article.
