Liệu một khối cuối cùng có chạy ngay cả khi bạn ném Ngoại lệ mới không?


142

Trong mã này sẽ someVarđược đặt ngay cả khi khối bắt được thực thi và Ngoại lệ thứ hai được ném?

public void someFunction() throws Exception {
    try {
        //CODE HERE
    } catch (Exception e) {
        Log.e(TAG, "", e);
        throw new Exception(e);
    } finally {
        this.someVar= true;
    }
}

2
Bởi vì có những trường hợp hành vi không được như mong đợi, như được chỉ ra bởi @GaryF
jax

1
Điều đáng chú ý là khối cuối cùng có thể không thực thi như mong đợi nếu nó ném ngoại lệ hoặc trả về.
Peter Lawrey

Câu trả lời:


184

Có, các khối cuối cùng luôn chạy ... ngoại trừ khi:

  • Chuỗi chạy khối thử-bắt-cuối bị giết hoặc gián đoạn
  • Bạn sử dụng System.exit(0);
  • VM bên dưới bị phá hủy theo một cách khác
  • Phần cứng bên dưới không thể sử dụng theo một cách nào đó

Ngoài ra, nếu một phương thức trong khối cuối cùng của bạn ném ra một ngoại lệ chưa được lưu, thì không có gì sau đó sẽ được thực thi (tức là ngoại lệ sẽ được ném như trong bất kỳ mã nào khác). Một trường hợp rất phổ biến trong đó điều này xảy ra là java.sql.Connection.close().

Bên cạnh đó, tôi đoán rằng mẫu mã bạn đã sử dụng chỉ là một ví dụ, nhưng hãy cẩn thận khi đưa logic thực tế vào trong một khối cuối cùng. Khối cuối cùng được dành cho việc dọn sạch tài nguyên (đóng các kết nối DB, giải phóng các xử lý tệp, v.v.), không phải cho logic phải chạy. Nếu nó phải chạy, hãy làm điều đó trước khối thử bắt, tránh xa thứ gì đó có thể ném ngoại lệ, vì ý định của bạn gần như chắc chắn là giống nhau.


4
Ý bạn là gì ở đây bởi "Chuỗi chạy khối thử-bắt-cuối cùng bị [...] bị gián đoạn"? Có lẽ tài liệu đó được diễn đạt kém, nhưng Thread.interrupt () sẽ không khiến khối cuối cùng bị bỏ qua, cho dù được ném từ khối thử hay khối bắt. Điều này có sử dụng "gián đoạn" để có nghĩa là một cái gì đó bạo lực hơn, như Thread.stop () không?
Joe Kearney

@Joe: Vâng, tôi nghĩ rằng tài liệu này hơi kém ở đây và chúng có nghĩa là sự gián đoạn chung cho hoạt động của chủ đề.
GaryF

@GaryF - Tôi nghĩ bạn đang trích dẫn từ JLS. Từ ngữ của JLS đôi khi hơi lạ, nhưng bạn thường sẽ thấy rằng ý nghĩa của thuật ngữ lạ được định nghĩa rõ ràng ở những nơi khác trong tài liệu. JLS là một đặc điểm kỹ thuật và có độ chính xác (chứ không phải dễ đọc) làm mục tiêu chính của nó.
Stephen C

1
@Stephen C - Trên thực tế, điều đó xuất phát từ hướng dẫn JavaSE (được liên kết với những người khác). Nó có thể được diễn đạt tương tự trong JLS, nhưng tôi không thể tìm thấy phần có liên quan. Tôi đã mong đợi điều này trong chương 11 (Ngoại lệ), chương 14 (Tuyên bố) hoặc chương 15 (Biểu thức), nhưng không thể thấy bất cứ điều gì đề cập đến sự gián đoạn một cách rõ ràng. Tôi chắc chắn sẽ thích thú khi thấy điều đó.
GaryF

1
@GaryF - Tôi hiểu rồi. Trên thực tế, JLS nói về việc chấm dứt các câu lệnh "bình thường" và "đột ngột" và có một phần (14.1) định nghĩa thuật ngữ này. Hành vi của finallysau đó được chỉ định trong điều khoản chấm dứt bình thường và đột ngột.
Stephen C

10

Đúng.

Xem tài liệu :

Khối cuối cùng luôn luôn thực thi khi khối thử thoát ra.

Ngoại lệ:

Lưu ý: Nếu JVM thoát trong khi mã thử hoặc bắt đang được thực thi, thì khối cuối cùng có thể không thực thi. Tương tự, nếu luồng thực thi mã thử hoặc bắt bị gián đoạn hoặc bị giết, khối cuối cùng có thể không thực thi mặc dù toàn bộ ứng dụng vẫn tiếp tục.


2

Cuối cùng, khối luôn luôn thực thi.

public class ExceptionTest {

public static void someFunction(String input) throws Exception {
    try {
        if( input.equals("ABC") ) {
            System.out.println("Matched");
        }
    } catch (Exception e) {
        throw new Exception(e);
    } finally {
        System.out.println("Input Is "+input+" Finally Executed!!!");
    }
}

/**
 * @param args
 */
public static void main(String[] args) {
    // TODO Auto-generated method stub
    try {
        System.out.println("********* Test with VALUE ********* ");
        someFunction("ABC");
        System.out.println("\r\n********* Test with NULL  ********* ");
        someFunction(null);
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

}

Java Thử Bắt Cuối cùng Chặn với Ném


2

Cuối cùng luôn luôn được thực thi, bất kể trường hợp của bạn là gì

  • thử-bắt-cuối cùng
  • ném

Đối với các trường hợp ngoại lệ không được kiểm tra, java không bắt buộc, xử lý lỗi. đây là lý do, nếu một ngoại lệ không được kiểm soát xảy ra trong khối cuối cùng và sau đó không xử lý được gì, thì mã được viết bên dưới điểm này (nơi xảy ra lỗi) sẽ không được thực thi.

Vì vậy, tôi đề nghị luôn luôn xử lý tất cả các ngoại lệ có thể được kiểm tra hoặc bỏ chọn. Bằng cách này, bạn có thể chắc chắn rằng khối mã cuối cùng cũng được thực thi bất kể nếu ngoại lệ không được kiểm tra cũng xảy ra. bạn có một vị trí trong tổ bắt phụ và cuối cùng chặn để hoàn thành công việc cần thiết của bạn.



1

Đúng. finallykhối thực thi luôn ngoại trừ trường hợp bạn gọi System.exit () vì nó dừng Java VM.


Các móc tắt máy vẫn được gọi sau System.exit (), nhưng các luồng không phải hệ thống hiện có đều bị dừng.
Peter Lawrey
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.