Tại sao chúng ta sử dụng các khối cuối cùng?


91

Theo như tôi có thể nói, cả hai đoạn mã sau sẽ phục vụ cùng một mục đích. Tại sao lại có finallykhối?

Mã A:

try { /* Some code */ }
catch { /* Exception handling code */ }
finally { /* Cleanup code */ }

Mã B:

try { /* Some code */ }
catch { /* Exception handling code */ }
// Cleanup code

Đây không phải là cụ thể cho C # nó là một câu hỏi Net
Sruly

1
Không cần thiết hơn với java7: AutomaticResourceManagement, thử (resourceDeclartion mới ()) {}
Kanagavelu Sugumar

Câu trả lời:


139
  • Điều gì xảy ra nếu một ngoại lệ mà bạn không xử lý bị ném ra? (Tôi hy vọng bạn không bắt được Throwable...)
  • Điều gì xảy ra nếu bạn quay lại từ bên trong khối thử?
  • Điều gì xảy ra nếu khối catch ném ra một ngoại lệ?

Một finallykhối đảm bảo rằng bạn thoát khỏi khối đó theo cách nào (mô đun một số cách hủy bỏ toàn bộ quá trình một cách rõ ràng), nó sẽ được thực thi. Điều đó quan trọng đối với việc dọn dẹp tài nguyên mang tính xác định.


48
Không nhất thiết phải đúng; cuối cùng sẽ không được thực thi nếu (1) có một System.exit()cuộc gọi (2) có một vòng lặp vô hạn trong thử hoặc một trong các khối catch (3) Tôi rút phích cắm trên máy tính
NullUserException

2
@Alon thử {return 1; } cuối cùng {retrun 2; } Bạn sẽ nhận được 2
Dennis C

19
@NullUserException: Do đó, bit "mô-đun một số cách ..."
Jon Skeet

2
John Skeet sống ở đây trên stackoverflow, mỗi câu hỏi giống như một hồi chuông cửa mà anh ấy phải trả lời :)
naikus

1
Bài đăng này thảo luận về các điều kiện (hiếm) mà cuối cùng KHÔNG ĐƯỢC gọi.
Candamir,

13

Lưu ý rằng (ít nhất là trong Java, có thể là cả trong C #), cũng có thể có một trykhối không có dấu catch, nhưng có một finally. Khi một ngoại lệ xảy ra trong trykhối, mã trongfinally khối sẽ được chạy trước khi ngoại lệ được đưa lên cao hơn:

InputStream in = new FileInputStream("somefile.xyz");
try {
    somethingThatMightThrowAnException();
}
finally {
    // cleanup here
    in.close();
}

7

Bạn có thể muốn đặt mã mà bạn muốn vẫn được thực thi bất kể điều gì xảy ra trong khối try hoặc catch của bạn.

Ngoài ra, nếu bạn đang sử dụng nhiều lệnh bắt và nếu bạn muốn đặt một số mã phổ biến cho tất cả các khối lệnh thì đây sẽ là nơi để đặt- nhưng bạn không thể chắc chắn rằng toàn bộ mã trong lần thử đã được thực thi.

Ví dụ:

conn c1 = new connection();
try {
    c1.dosomething();
} catch (ExceptionA exa) {
    handleexA();
    //c1.close();
} catch (ExceptionB exb) {
    handleexB();
    //c1.close();
} finally {
    c1.close();
}

1
Điều gì sẽ xảy ra nếu tôi không sử dụng 'cuối cùng' mà đóng kết nối?
Istiaque Ahmed

5

Cuối cùng luôn được thực thi, vì mã của bạn sau khi bắt có thể không.


1
tại sao không! Nếu ngoại lệ được xử lý đúng cách, mã sẽ được thực thi một cách dứt khoát.
Mohammad Nadeem

1
@Nadeem: Xem câu trả lời của tôi vì 3 lý do nó có thể không xảy ra.
Jon Skeet

2

Mặc dù ứng dụng của chúng ta bị đóng một cách cưỡng bức, nhưng sẽ có một số tác vụ mà chúng ta phải thực hiện (như giải phóng bộ nhớ, đóng cơ sở dữ liệu, khóa phát hành, v.v.), nếu bạn viết những dòng mã này trong finallykhối, nó sẽ thực thi cho dù một ngoại lệ được ném ra hay không phải...

Ứng dụng của bạn có thể là một tập hợp các luồng, Exceptionkết thúc luồng nhưng không phải là toàn bộ ứng dụng, trong trường hợp finallynày hữu ích hơn.

Trong một số trường hợp finallysẽ không thực thi chẳng hạn như JVM Fail, Thread chấm dứt, v.v.


1

Vì bạn cần mã đó để thực thi bất kể trường hợp ngoại lệ nào có thể được ném ra. Ví dụ: bạn có thể cần phải dọn dẹp một số tài nguyên không được quản lý (cấu trúc 'using' biên dịch thành một khối thử / cuối cùng).


0

Có thể có lúc bạn muốn thực thi một đoạn mã bất kể điều gì. Cho dù một ngoại lệ được ném ra hay không. Sau đó, một sử dụng finally.


0

finallyLUÔN LUÔN thực thi, trừ khi JVM bị tắt, finallychỉ cần cung cấp một phương pháp để đặt mã dọn dẹp ở một nơi.

Sẽ quá tẻ nhạt nếu bạn phải đặt mã dọn dẹp vào từng catchkhối.


0

Nếu khối catch ném ra bất kỳ ngoại lệ nào thì mã còn lại sẽ không được thực thi do đó chúng ta phải viết khối finaly.


0

cuối cùng khối trong java có thể được sử dụng để đặt mã "dọn dẹp" chẳng hạn như đóng tệp, đóng kết nối, v.v.


Khối cuối cùng sẽ không được thực thi nếu chương trình thoát (bằng cách gọi System.exit () hoặc bằng cách gây ra lỗi nghiêm trọng khiến quá trình bị hủy bỏ).


0

Vẫn cuộn xuống? Của bạn đây!

Câu hỏi này đã cho tôi một khoảng thời gian khó khăn.

try
{
 int a=1;
 int b=0;
 int c=a/b;
}
catch(Exception ex)
{
 console.writeline(ex.Message);
}
finally
{
 console.writeline("Finally block");
}
console.writeline("After finally");

những gì sẽ được in trong kịch bản trên? Có đoán nó đúng:

  • ví dụ: Tin nhắn - bất kể nó là gì (có thể đã cố gắng chia cho 0)

  • Cuối cùng là khối

  • Sau cùng

    try
    {
        int a=1;
        int b=0;
        int c=a/b;
    }
    catch(Exception ex)
    {
        throw(ex);
    }
    finally
    {
        console.writeline("Finally block");
    }
    console.writeline("After finally");
    

Điều này sẽ in gì? Không có gì! Nó tạo ra một lỗi vì khối bắt lỗi tạo ra lỗi.

Trong một cấu trúc lập trình tốt, các ngoại lệ của bạn sẽ được sắp xếp theo nghĩa là mã này sẽ được xử lý từ một lớp khác. Để kích thích một trường hợp như vậy, tôi sẽ lồng nhau thử mã này.

try
{    
 try
    {
     int a=1;
     int b=0;
     int c=a/b;
    }
    catch(Exception ex)
    {
     throw(ex);
    }
    finally
    {
     console.writeline("Finally block")
    }
    console.writeline("After finally");
}
catch(Exception ex)
{
 console.writeline(ex.Message);
}

Trong trường hợp này, đầu ra sẽ là:

  • Cuối cùng là khối
  • ví dụ: Tin nhắn - bất kể nó là gì.

Rõ ràng là khi bạn bắt một ngoại lệ và ném lại vào các lớp khác (Funneling), mã sau khi ném sẽ không được thực thi. Nó hoạt động tương tự như cách trả về bên trong một hàm hoạt động.

Bây giờ bạn biết tại sao không đóng tài nguyên của mình trên các mã sau khối bắt. Hãy đặt chúng vào khối cuối cùng.

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.