簡體   English   中英

finally 塊的重點是什么?

[英]What is the point of the finally block?

撇開語法不談,兩者之間有什么區別

try {
}
catch() {
}
finally {
    x = 3;
}

try {
}
catch() {
}

x = 3;

編輯:在 .NET 2.0 中?


所以

try {
    throw something maybe
    x = 3
}
catch (...) {
    x = 3
}

在行為上是等價的嗎?

好吧,首先,如果您在try塊中返回,則finally仍將運行,但try-catch-finally塊下面列出的代碼不會。

取決於語言,因為可能存在一些輕微的語義差異,但想法是它將(幾乎)始終執行,即使try塊中的代碼引發異常。

在第二個示例中,如果catch塊中的代碼返回或退出,則不會執行x = 3。 在第一個它會。

在.NET平台中,在某些情況下不會發生finally塊的執行:安全異常,線程暫停,計算機關閉:)等。

在Java中:

最后總是被調用,無論異常是否在catch()中被正確捕獲,或者實際上如果你有一個catch。

最后嘗試抓住是非常重要的構造。 您可以確定即使拋出異常,也會執行finally塊中的代碼。 處理外部資源以釋放它們非常重要。 垃圾收集不會為您做到這一點。 在最后一部分,你不應該有return語句或拋出異常。 這樣做是可能的,但這是一種不好的做法,可能導致不可預測的結果。

如果您嘗試此示例:

try {
  return 0;
} finally {
  return 2;
}

結果將是2 :)

與其他語言的比較: 從最后回歸

有幾件事使得finally塊有用:

  1. 如果從try或catch塊返回,則在將控制權返回給調用函數之前,仍然會執行finally塊
  2. 如果catch塊中發生異常,或者try塊中發生未捕獲類型的異常,則仍會執行finally塊中的代碼。

這些使得finally塊非常適合關閉文件句柄或套接字。

在這種情況下,嘗試和捕獲是空的,沒有區別。 否則你可以肯定,最終將被執行。

例如,如果你在catchblock(rethrow)中拋出一個新的Exception,那么只有在finally塊中才會執行賦值。

通常使用finally來自行清理(關閉數據庫連接,文件句柄等)。

你永遠不應該在最后使用控制語句(return,break,continue),因為這可能是一個維護噩夢,因此被認為是不好的做法

即使拋出異常或達到return語句(盡管可能依賴於語言),finally塊也將始終被調用(並非總是 ......)。 這是一種清理你知道永遠會被召喚的方法。

@iAn和@mats:

我不會在try {}中“設置”最終{}中的任何內容“拆除”作為規則。 最好在try {}之外提取流創建。 如果您需要在流上處理異常,則可以在更大的范圍內完成此操作。

StreamReader stream = new StreamReader("foo.bar");  
try {
    mySendSomethingToStream(stream);
}
catch(noSomethingToSendException e) {
    //Swallow this    
    logger.error(e.getMessage());
}
catch(anotherTypeOfException e) {
    //More serious, throw this one back
    throw(e);
}
finally {
    stream.close();  
}

這個問題很,但這一直困擾着我(我在這里找到它是有原因的)。 我已經閱讀了每個答案,在我看來,沒有人真正考慮過。

這不是一個答案。 我真的認為finally沒有什么好處,這可能就是為什么它直到“最近”才在編程語言中存在的原因。 大多數說明stream.close()的示例會導致空引用異常,因此您仍然需要測試它是否為空。

是的,如果你從try{}返回, finally仍然會運行。 但這是好的做法嗎? 看來是女漢子,還不如把goto帶回來。 為什么不在阻塞后等待並返回? finally {}所做的就是在您的代碼中添加兩三行。

在Java中,無論您是使用“返回”,只是通過try塊運行還是捕獲了異常,都可以將它用於您要執行的任何操作。

例如,關閉數據庫會話或JMS連接,或取消分配某些OS資源。

我猜它在.NET中是類似的?

因此,您可以清理在try塊中初始化的任何打開的連接等。 如果您打開了連接然后發生了異常,則不會正確關閉該異常。 這種情況是finally塊的用途。

無論你是否捕獲了異常,finally塊都應該執行。 請參閱Try / Catch / Finally示例

@Ed ,你可能會想到像catch(...)這樣的東西在C ++中捕獲一個非指定的異常。

finally是無論catch塊發生什么都會執行的代碼。

Microsoft在C#的try-finally上有一個幫助頁面

finally塊與try / catch在同一范圍內,因此您可以訪問內部定義的所有變量。

想象一下,你有一個文件處理程序,這與它的編寫方式不同。

try
{
   StreamReader stream = new StreamReader("foo.bar");
   stream.write("foo");
}
catch(Exception e) { } // ignore for now
finally
{
   stream.close();
}

相比

StreamReader stream = null;
try
{
    stream = new StreamReader("foo.bar");
    stream.write("foo");
} catch(Exception e) {} // ignore

if (stream != null)
    stream.close();

請記住,最終內部的任何內容都無法保證運行。 想象一下,你得到一個中止信號,窗戶崩潰或電源消失。 最終依賴於業務關鍵代碼是不好的。

如果出現未處理的異常,則finally中的任何代碼都會運行。 通常,finally代碼用於使用.dispose()清除非托管代碼的本地聲明。

最后塊允許你作為一個開發人員自己整理,不管try {}塊中前面代碼的操作遇到錯誤,並且讓其他人指出這一點,主要是在釋放資源的保護傘下 - 關閉指針/套接字/結果集,返回池的連接等。

@mats是非常正確的,總是存在“硬”失敗的可能性 - 最后塊不應該包含任務關鍵代碼,這應該總是在try {}內部以事務方式完成

@mats再次 - 真正的美麗是它允許你從自己的方法中拋出異常,並仍然保證你整理:

try
{
StreamReader stream = new StreamReader("foo.bar");
mySendSomethingToStream(stream);
}
catch(noSomethingToSendException e) {
    //Swallow this    
    logger.error(e.getMessage());
}
catch(anotherTypeOfException e) {
    //More serious, throw this one back
    throw(e);
}
finally
{
stream.close();
}

因此,我們可以捕獲許多類型的異常,以不同的方式處理它們(第一個允許執行try {}以外的任何事情,第二個有效地返回),但總是整齊而整齊地清理。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM