2010-05-08 63 views
3

我無法在Java中發現任何有關一些清理操作的建議,這些清理操作本身可能會引發異常。在Java中使用清理操作編寫catch塊

典型的例子是stream.close(),我們通常在finally子句中調用它,如果拋出異常,我們可以通過在try-catch塊中調用它或者聲明它被重新拋出來忽略它。

但在一般情況下,我怎麼處理這樣的情況:

public void doIt() throws ApiException { //ApiException is my "higher level" exception 
    try { 
    doLower(); 
    } catch(Exception le) { 
    doCleanup(); //this throws exception too which I can't communicate to caller 
    throw new ApiException(le); 
    } 
} 

我可以這樣做:

catch(Exception le) { 
    try { 
    doCleanup(); 
    } catch(Exception le1) { 
    //ignore? 
    //log? 
    } 
    throw new ApiException(le); //I must throw le 
} 

但這意味着我將不得不做一些日誌分析理解爲什麼清理失敗。

如果我這樣做:

catch(Exception le) { 
    try { 
    doCleanup(); 
    } catch(Exception le1) { 
    throw new ApiException(le1); 
    } 

它導致失去這讓我在這裏的拳頭地方catch塊le

人們在這裏使用的一些成語是什麼?

  • 在throws子句中聲明較低級別的異常?
  • 忽略清理操作中的異常?

回答

0

使用finally塊。如果你擔心吞嚥堆棧跟蹤執行以下操作:

Exception ex = new Exception(le.stackTrace()); 
+0

我不確定。首先,有兩個異常來源,因此我不確定最終放置的位置,其次,我猜你的意思是Throwable上的setStackTrace()方法。我們沒有接受堆棧跟蹤的Exception構造函數。 – 2010-05-08 02:28:40

3

首先,決定你是否真的需要從finally塊拋出 - 仔細想想上 - 在一個失敗的close()調用的情況下。 ..好吧,記錄它是好的 - 但你的API的更高層真的可以解決這個問題呢?因此,對於99%的情況,您將記錄中學教材,然後重新投擲主教材。

接下來,如果您確實需要拋出次級,請確定次要異常的各種原因是否重要。它們很罕見。因此,將次要原因設置爲主要(使用適當的構造函數或initCause())。

最後,如果您必須拋出輔助節點,並保留輔助節點和主節點的完整堆棧跟蹤 - 那麼您需要創建自定義異常來處理這種情況。這很醜陋,因爲你可能想要從不同的父類中派生出來。如果出現這種情況,我建議創建一個輔助類,它能夠填充目標異常的堆棧跟蹤,以便根據這兩種異常生成有意義的跟蹤(確保爲次要使用縮進,因此嵌套的異常是容易拉開)。

但大多數情況下,我建議您使用log-and-rethrow-primary範例。專注於修復主要問題,而次要問題通常會自行處理(這裏的經典示例是IO異常,使得事情變得非常糟糕,以至於調用close()也無法成功)。