Khối Lệnh finally (The Finally Block)

Khối lệnh finally trong Java là một khối mã đặc biệt luôn được thực thi, bất kể có ngoại lệ xảy ra trong khối try hay không, trừ khi chương trình bị chấm dứt đột ngột (ví dụ: lỗi hệ thống nghiêm trọng). Nó thường được sử dụng để thực hiện các tác vụ dọn dẹp như đóng kết nối, đóng file, giải phóng tài nguyên, v.v.

Lưu ý:

↳ Khối finally không được thực thi nếu chương trình bị chấm dứt đột ngột (ví dụ: lỗi hệ thống nghiêm trọng).

↳ Nếu có câu lệnh return trong khối try hoặc catch, khối finally sẽ vẫn được thực thi trước khi trả về.

↳ Ngay cả khi không có khối catch nào xử lý ngoại lệ, hoặc ngoại lệ được ném ra mà không được bắt, khối finally vẫn sẽ được thực thi trước khi chương trình kết thúc (trừ khi có một lỗi hệ thống nghiêm trọng khiến JVM phải dừng đột ngột).

Cách hoạt động của khối lệnh finally trong Java - minh họa
Ảnh mô tả cách hoạt động của khối lệnh finally.

Tại sao sử dụng khối finally:

↳ Đảm bảo giải phóng tài nguyên như đóng file, kết nối mạng.

↳ Thực hiện các tác vụ dọn dẹp sau khi xử lý ngoại lệ hoặc không có ngoại lệ.

↳ Tránh rò rỉ tài nguyên.

Cách sử dụng khối finally trong java

Trường hợp 1: Sử dụng khối lệnh finally trong trường hợp ngoại lệ không xảy ra.

Khi không có ngoại lệ xảy ra trong khối try, các câu lệnh trong khối try sẽ được thực thi bình thường và khối finally sẽ luôn được thực thi.

Ví dụ: Example.java

public class Example {
    public static void main(String[] args) {
        try {
            System.out.println("Bắt đầu khối try");
            // Không có ngoại lệ xảy ra
            System.out.println("Kết thúc khối try");
        } catch (Exception e) {
            System.out.println("Khối catch");
        } finally {
            System.out.println("Khối finally");
        }
        
        System.out.println("Chương trình tiếp tục chạy");
    }
}

Kết quả của chương trình là:

Bắt đầu khối try
Kết thúc khối try
Khối finally
Chương trình tiếp tục chạy

Trường hợp 2: Sử dụng khối lệnh finally trong trường hợp ngoại lệ xảy ra nhưng không được khối catch xử lý.

Khi ngoại lệ xảy ra nhưng không được xử lý bởi khối catch, chương trình sẽ kết thúc đột ngột sau khi khối finally được thực thi.

Ví dụ: Example.java

public class Example {
    public static void main(String[] args) {
        try {
            System.out.println("Bắt đầu khối try");
            int result = 10 / 0; // Gây ra ArithmeticException
            System.out.println("Kết thúc khối try");
        } catch (NullPointerException e) {
            System.out.println("Khối catch");
        } finally {
            System.out.println("Khối finally");
        }
        
        System.out.println("Chương trình tiếp tục chạy");
    }
}

Kết quả của chương trình là:

Bắt đầu khối try
Khối finally
Exception in thread "main" java.lang.ArithmeticException: / by zero at Example.main(Example.java:5)

Trường hợp 3: Sử dụng khối lệnh finally trong trường hợp ngoại lệ xảy ra và được khối catch xử lý.

Khi ngoại lệ xảy ra và được xử lý bởi khối catch, khối finally sẽ được thực thi sau khối catch.

Ví dụ: Example.java

public class Example {
    public static void main(String[] args) {
        try {
            System.out.println("Bắt đầu khối try");
            int result = 10 / 0; // Gây ra ArithmeticException
            System.out.println("Kết thúc khối try");
        } catch (ArithmeticException e) {
            System.out.println("Khối catch: " + e.getMessage());
        } finally {
            System.out.println("Khối finally");
        }
        
        System.out.println("Chương trình tiếp tục chạy");
    }
}

Kết quả của chương trình là:

Bắt đầu khối try
Khối catch: / by zero
Khối finally
Chương trình tiếp tục chạy

Trường hợp 4: Sử dụng khối lệnh finally trong trường hợp trong khối try có lệnh return.

Khi có lệnh return trong khối try, khối finally sẽ vẫn được thực thi trước khi phương thức trả về giá trị.

Ví dụ: Example.java

public class Example {
    public static void main(String[] args) {
        System.out.println("Giá trị trả về: " + testMethod());
    }

    public static int testMethod() {
        try {
            System.out.println("Bắt đầu khối try");
            return 10;
        } catch (Exception e) {
            System.out.println("Khối catch");
        } finally {
            System.out.println("Khối finally");
        }
        return 0;
    }
}

Kết quả của chương trình là:

Bắt đầu khối try
Khối finally
Giá trị trả về: 10

Trường hợp đặc biệt với System.exit() và ngoại lệ trong finally

1. System.exit() và khối finally

Khi gọi System.exit() trong khối try hoặc catch, chương trình sẽ kết thúc ngay lập tức, và khối finally sẽ không được thực thi. System.exit() yêu cầu JVM kết thúc ngay lập tức, bỏ qua tất cả các khối finally.

Ví dụ: Example.java

public class Example {
    public static void main(String[] args) {
        try {
            System.out.println("Bắt đầu khối try");
            System.exit(0); // Kết thúc chương trình ngay lập tức
        } finally {
            System.out.println("Khối finally sẽ không được thực thi");
        }
        
        System.out.println("Dòng này sẽ không được thực thi");
    }
}

Kết quả của chương trình là:

Bắt đầu khối try

Chương trình kết thúc ngay sau lệnh System.exit(0), vì vậy khối finally và dòng cuối cùng không được thực thi.

2. Ngoại lệ trong khối finally

Nếu có ngoại lệ được ném ra trong khối finally, nó sẽ che khuất (suppress) bất kỳ ngoại lệ nào đã được ném ra trong khối try hoặc catch. Điều này có nghĩa là ngoại lệ trong khối finally sẽ là ngoại lệ chính mà bạn thấy.

Ví dụ: Example.java

public class Example {
    public static void main(String[] args) {
        try {
            System.out.println("Bắt đầu khối try");
            int result = 10 / 0; // Gây ra ArithmeticException
        } catch (ArithmeticException e) {
            System.out.println("Ngoại lệ: Chia cho 0");
        } finally {
            System.out.println("Khối finally được thực thi");
            int a = 10 / 0; // Gây ra ngoại lệ trong khối finally
        }
    }
}

Kết quả của chương trình là:

Bắt đầu khối try
Ngoại lệ: Chia cho 0
Khối finally được thực thi
Exception in thread "main" java.lang.ArithmeticException: / by zero at Example.main(Example.java:10)

Ngoại lệ trong finally: Ngoại lệ trong khối finally sẽ che khuất các ngoại lệ từ khối try hoặc catch, khiến nó trở thành ngoại lệ chính được ném ra.

Câu Nói Truyền Cảm Hứng

“Bắt đầu ở đâu không quan trọng, quan trọng là bạn sẵn sàng bắt đầu.” – W. Clement Stone

Không Gian Tích Cực

“Chúc bạn luôn giữ vững niềm tin và sức mạnh để vượt qua mọi thử thách trong cuộc sống.”