Ngoại lệ (exceptions) có thể làm chương trình kết thúc bất thường. Do đó, xử lý ngoại lệ là công việc quan trọng mà lập trình việc phải lưu ý. Chúng ta có thể xử lý ngoại lệ với những cách sau trong Java:
- Sử dụng try…catch
- Sử dụng try…catch…finally
- Sử dụng throw và throws
1. Xử lý exceptions trong Java với try…catch
Có thể sử dụng try…catch để xử lý ngoại lệ trong Java. Cú pháp:
try {
// code
}
catch(Exception e) {
// code
}
Khi một exception xảy ra trong khối lệnh try thì nó sẽ được ném cho khối lệnh catch xử lý mà không làm cho chương trình bị kết thúc bất thường. Lưu ý: Có thể chỉ có khối lệnh try mà không có khối lệnh catch. Nhưng khi có khối lệnh catch thì bắt buộc phải có khối lệnh try. Ví dụ:
class Main {
public static void main(String[] args) {
try {
//các lệnh có thể sinh ra exception
int divideByZero = 5 / 0;
System.out.println("Rest of code in try block");
}catch (ArithmeticException e) {
System.out.println("ArithmeticException => " + e.getMessage());
}
}
}
Kết quả
ArithmeticException => / by zero
Trong ví dụ trên, chúng ta thực hiện phép chia cho 0 nên sẽ sinh ra exception. Exception này xảy ra thì các lệnh trong try sẽ bị bỏ qua và sẽ ném exception cho khối lệnh catch. Khối lệnh catch bắt được exception và được xử lý trong catch.
Nếu các lệnh trong try không sinh ra ngoại lệ thì khối lệnh catch sẽ được bỏ qua.
Có thể bắt nhiều exception với một khối lệnh catch
class Main {
public static void main(String[] args) {
try {
int array[] = new int[10];
array[10] = 30 / 0;
} catch (ArithmeticException | ArrayIndexOutOfBoundsException e) {
System.out.println(e.getMessage());
}
}
}
Có thể sử dụng nhiều khối lệnh catch với try
class ListOfNumbers {
public int[] arr = new int[10];
public void writeList() {
try {
arr[10] = 11;
}
catch (NumberFormatException e1) {
System.out.println("NumberFormatException => " + e1.getMessage());
}
catch (IndexOutOfBoundsException e2) {
System.out.println("IndexOutOfBoundsException => " + e2.getMessage());
}
}
}
class Main {
public static void main(String[] args) {
ListOfNumbers list = new ListOfNumbers();
list.writeList();
}
}
2. Xử lý exceptions trong Java với try…catch…finally
Trong Java, khối lệnh finally luôn luôn được thực thi bất kể có xảy ra ngoại lệ hay không. Khối lệnh finally có thể có hoặc không là do lập trình viên sử dụng. Mỗi khối lệnh try sẽ chỉ có một khối lệnh finally. Cú pháp:
try {
//code
}
catch (ExceptionType1 e1) {
// catch block
}
finally {
// finally block always executes
}
Có một số trường hợp chúng ta nên sử dụng finally. Ví dụ, trường hợp mở một file để đọc và ghi dữ liệu vào file. Sau khi mọi thao tác với file hoàn tất thì phải đóng kết nối để trả file lại cho các chương trình khác sử dụng. Việc đóng kết nối file phải được thực thi mặc dù có xảy ra exception trong quá trình thao tác với file hay không.
import java.io.FileReader;
import java.io.IOException;
class Main {
public static void main(String args[]) {
FileReader fileReader = null;
try {
fileReader = new FileReader("D:\\test.txt");
// do something
} catch (Exception ex) {
ex.printStackTrace();
} finally {
try {
if(fileReader != null) {
fileReader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Khối lênh try…finally trong Java
Trong Java, chúng ta có thể sử dụng finally với try mà không cần catch. Không khuyến kích sử dụng như thế này bởi exception sẽ không được xử lý bởi catch nếu xảy ra.
class Main {
public static void main(String[] args) {
try {
int divideByZero = 5 / 0;
}
finally {
System.out.println("Finally block is always executed");
}
}
}
Kết quả
Finally block is always executed
Exception in thread "main" java.lang.ArithmeticException: / by zero
at anotherPackage.Main.main(Main.java:6)
3. Xử lý exceptions trong Java với throws và throw
3.1. Từ khóa throws trong Java
Trong Java, chúng ta sử dụng từ khóa throws trong khai báo phương thức để khai báo những ngoại lệ (exceptions) có thể xảy ra trong phương thức đó. Chúng ta có thể nói là throws ném các ngoại lệ của phương thức ra bên ngoài.
Lưu ý: Lập trình viên phải đoán biết trước những loại ngoại lệ của phương thức để khai báo cho chính xác.
Cú pháp của sử dụng throws:
accessModifier returnType methodName() throws ExceptionType1, ExceptionType2 … {
// code
}
Ví dụ:
import java.io.*;
class Main {
public static void findFile() throws FileNotFoundException {
//code that may produce IOException
File newFile=new File("test.txt");
FileInputStream stream=new FileInputStream(newFile);
}
public static void main(String[] args) {
try{
findFile();
} catch(IOException e){
System.out.println(e);
}
}
}
Kết quả
java.io.FileNotFoundException: test.txt (The system cannot find the file specified)
Trong ví dụ trên, hàm khởi tạo FileInputStream()
đã được khai báo ngoại lệ FileNotFoundException. Hàm findFile()
sử dụng hàm khởi tạo này cũng phải khai báo ngoại lệ FileNotFoundException. Sau đó, trong hàm main()
, chúng ta gọi hàm findFile()
thì dùng try…catch để bắt ngoại lệ.
public FileInputStream(File file) throws FileNotFoundException {
String name = (file != null ? file.getPath() : null);
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkRead(name);
}
if (name == null) {
throw new NullPointerException();
}
if (file.isInvalid()) {
throw new FileNotFoundException("Invalid file path");
}
fd = new FileDescriptor();
fd.attach(this);
path = name;
open(name);
}
Chúng ta có thể khai báo nhiều ngoại lệ có thể xảy ra khi thực thi phương thức. Ví dụ:
import java.io.*;
class Main {
public static void findFile() throws NullPointerException, IOException, InvalidClassException {
// code that may produce NullPointerException
… … …
// code that may produce IOException
… … …
// code that may produce InvalidClassException
… … …
}
public static void main(String[] args) {
try{
findFile();
} catch(IOException e1){
System.out.println(e1.getMessage());
} catch(InvalidClassException e2){
System.out.println(e2.getMessage());
}
}
}
3.2. Từ khóa throw trong Java
Từ khóa throw được sử dụng để khai báo một ngoại lệ cụ thể bên trong phương thức. Chúng ta có thể định nghĩa thông báo (message) của ngoại lệ với từ khóa throw. Ngoại lệ được khai báo bởi throw sẽ được ném cho ngoại lệ được khai báo với throws của phương thức. Ví dụ:
import java.io.*;
class Main {
public static void findFile() throws IOException {
//code that may produce IOException
File newFile=new File("test.txt");
if(newFile.exists() && !newFile.isDirectory()) {
// do something
}else{
throw new IOException("File not found");
}
}
public static void main(String[] args) {
try{
findFile();
} catch(IOException e){
System.out.println(e);
}
}
}
Kết quả
java.io.IOException: File not found
Trong ví dụ trên, nếu không tìm thấy file thì sẽ ném ngoại lệ với từ khóa throw:
throw new IOException("File not found");
Phương thức findFile()
cũng phải có throws IOException để bắt ngoại lệ được ném ra. Khi gọi hàm findFile()
trong hàm main()
thì dùng try…catch để bắt ngoại lệ.