[英]In .NET, what if something fails in the catch block, will finally always get called?
[英]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塊有用:
這些使得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.