Java: Cách sử dụng try-catch-finally

Các khóa học qua video:
Python SQL Server PHP C# Lập trình C Java HTML5-CSS3-JavaScript
Học trên YouTube <76K/tháng. Đăng ký Hội viên
Viết nhanh hơn - Học tốt hơn
Giải phóng thời gian, khai phóng năng lực

Những bài viết trước đã mô tả cách xây dựng các khối mã trycatch và finally cho phương thức writeList trong lớp ListOfNumbers. Bây giờ, ta hãy đi bộ qua khối mã và xem những gì có thể xảy ra.

Khi tất cả các thành phần được đặt lại với nhau thì phương thức writeList trông giống như sau:

public void writeList() {
    PrintWriter out = null;

    try {
        System.out.println("Đang ở trong khối try");

        out = new PrintWriter(new FileWriter("OutFile.txt"));
        for (int i = 0; i < SIZE; i++) {
            out.println("Giá trị tại: " + i + " = " + list.get(i));
        }
    } catch (IndexOutOfBoundsException e) {
        System.err.println("Đã bắt IndexOutOfBoundsException: " + e.getMessage());

    } catch (IOException e) {
        System.err.println("Đã bắt IOException: " +  e.getMessage());

    } finally {
        if (out != null) {
            System.out.println("Đang đóng PrintWriter");
            out.close();
        }
        else {
            System.out.println("PrintWriter không mở");
        }
    }
}

Như đã đề cập, khối try của phương thức này có ba khả năng thoát khác nhau, dưới đây là hai trong số đó.

  1. Mã lệnh trong khối try thất bại và ném một ngoại lệ, ngoại lệ này có thể là một IOException gây ra bởi câu lệnh new FileWriter hoặc một ngoại lệ IndexOutOfBoundsException gây ra bởi một giá trị chỉ số sai trong vòng lặp for.
  2. Tất cả đều thành công và câu lệnh try thoát bình thường.

Ta hãy xem điều gì sẽ xảy ra trong phương thức writeList với hai khả năng thoát trên.

Kịch bản 1: Xảy ra một ngoại lệ

Câu lệnh tạo một FileWriter có thể thất bại vì một số lý do. Ví dụ, hàm tạo cho FileWriter ném một IOException nếu chương trình không thể tạo hoặc ghi vào tập tin được chỉ định.

Khi FileWriter ném một IOException, hệ thống thời gian chạy ngay lập tức dừng thực hiện khối try; các lời gọi phương thức đang được thực thi sẽ không được hoàn thành. Hệ thống thời gian chạy sau đó bắt đầu tìm kiếm phương thức ở trên cùng cho một trình xử lý ngoại lệ thích hợp. Trong ví dụ này, khi IOException xảy ra thì hàm tạo FileWriter sẽ nằm ở đầu của call stack. Tuy nhiên, hàm tạo FileWriter  không có một trình xử lý ngoại lệ nào thích hợp, vì vậy hệ thống thời gian chạy sẽ kiểm tra phương thức tiếp theo - phương thức writeList - trong call stack. Phương thức writeList có hai trình xử lý ngoại lệ: một cho IOException và một cho IndexOutOfBoundsException.

Hệ thống thời gian chạy kiểm tra các trình xử lý của writeList theo thứ tự mà chúng xuất hiện sau câu lệnh try. Tham số tới trình xử lý ngoại lệ đầu tiên là IndexOutOfBoundsException. Điều này không phù hợp với kiểu của ngoại lệ đã ném, vì vậy hệ thống thời gian chạy kiểm tra trình xử lý ngoại lệ tiếp theo - IOException. Trình xử lý này phù hợp với loại ngoại lệ được ném ra, vì vậy hệ thống runtime kết thúc tìm kiếm của mình cho một trình xử lý ngoại lệ thích hợp. Bây giờ thời gian chạy đã tìm thấy một trình xử lý thích hợp, mã lệnh trong khối catch sẽ được thực thi.

Sau khi trình xử lý ngoại lệ được thực thi, hệ thống runtime sẽ chuyển quyền điều khiển đến khối finally. Mã lệnh trong finally được thực thi bất kể các ngoại lệ có được bắt hay không. Trong kịch bản này, FileWriter không bao giờ được mở và vì vậy không cần phải đóng. Sau khi khối finally kết thúc thực hiện, chương trình tiếp tục với câu lệnh đầu tiên sau khối finally.

Đây là đầu ra hoàn chỉnh từ chương trình ListOfNumbers xuất hiện khi một IOException được ném ra.

Đang ở trong khối try
Đã bắt IOException: OutFile.txt
PrintWriter không mở

Các câu lênh in đậm dưới đây là những câu lệnh được thực thi trong kịch bản này:

public void writeList() {
   PrintWriter out = null;

    try {
        System.out.println("Đang ở trong khối try");
        out = new PrintWriter(new FileWriter("OutFile.txt"));
        for (int i = 0; i < SIZE; i++)
            out.println("Giá trị tại: " + i + " = " + list.get(i));

    } catch (IndexOutOfBoundsException e) {
        System.err.println("Đã bắt IndexOutOfBoundsException: " + e.getMessage());

    } catch (IOException e) {
        System.err.println("Caught IOException: " + e.getMessage());
    } finally {
        if (out != null) {

            System.out.println("Đang đóng PrintWriter");
            out.close();
        }
        else {
            System.out.println("PrintWriter không mở");
        }

    }
}

Kịch bản 2: Khối try thoát bình thường

Trong kịch bản này, tất cả các câu lệnh trong phạm vi của khối try thực hiện thành công và không ném ngoại lệ nào. Sự thực thi bị lỗi ở phía cuối của khối try, và hệ thống thời gian chạy sẽ chuyển quyền điều khiển đến khối finally. Do mọi thứ đã thành công, nên PrintWriter sẽ được mở khi quyền điều khiển được chuyển đến khối finally để đóng PrintWriter. Một lần nữa, sau khi khối finally kết thúc thực hiện thì chương sẽ tiếp tục với câu lệnh đầu tiên sau khối finally.

Đây là kết quả từ chương trình ListOfNumbers khi không có ngoại lệ nào được ném ra:

Đang ở trong khối try
Đang đóng PrintWriter

Các câu lệnh bôi đen trong ví dụ sau là các câu lệnh được thực thi trong kịch bản này:

public void writeList() {
    PrintWriter out = null;
    try {
        System.out.println("Đang ở trong khối try");
        out = new PrintWriter(new FileWriter("OutFile.txt"));
        for (int i = 0; i < SIZE; i++)
            out.println("Giá trị tại: " + i + " = " + list.get(i));

    } catch (IndexOutOfBoundsException e) {
        System.err.println("Đã bắt IndexOutOfBoundsException: " + e.getMessage());

    } catch (IOException e) {
        System.err.println("Đã bắt IOException: " + e.getMessage());

    } finally {
        if (out != null) {
            System.out.println("Đang đóng PrintWriter");
            out.close();
        }

        else {
            System.out.println("PrintWriter không mở");
        }
    }
}

» Tiếp: Xác định những ngoại lệ được ném bởi một phương thức
« Trước: Câu lệnh try-with-resources
Các khóa học qua video:
Python SQL Server PHP C# Lập trình C Java HTML5-CSS3-JavaScript
Học trên YouTube <76K/tháng. Đăng ký Hội viên
Viết nhanh hơn - Học tốt hơn
Giải phóng thời gian, khai phóng năng lực
Copied !!!