2013-10-24 76 views
13

對於在try/catch塊中放入多少代碼是否存在「最佳做法」?要在try-catch塊中放入多少代碼

我在下面發佈了3種不同的場景。

我沒有在每個catch塊中包含行爲,並且我沒有包含finally塊。這是爲了提高觀衆的可讀性。假設每個catch做了不同的事情。並假設finally將關閉流。試圖爲未來的讀者創建一個易於閱讀的示例。

  1. Control,no try/catch
  2. 每個需要的地方代碼爲1 try/catch
  3. 只有1個try/catch周圍整個代碼塊的代碼。

什麼是公認的最佳實踐,爲什麼?


方案1

代碼,而無需try/catch,只是控制。

BufferedReader bufferedReader = new BufferedReader(new FileReader("somepath")); 
    String line; 
    while ((line = bufferedReader.readLine()) != null) { 
     Object object = new Object(); 
     this.doSomething(object); 
    } 
    bufferedReader.close(); 

方案2

代碼與try/catch塊爲所需的每個單獨的位置。

BufferedReader bufferedReader = null; 
    try { 
     bufferedReader = new BufferedReader(new FileReader("somepath")); 
    } catch (FileNotFoundException e) { 
     e.printStackTrace(); 
    } 
    String line; 
    try { 
     while ((line = bufferedReader.readLine()) != null) { 
      Object object = new Object(); 
      this.doSomething(object); 
     } 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
    try { 
     bufferedReader.close(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 

方案3

代碼與1 try/catch的代碼整個塊周圍。

try { 
     BufferedReader bufferedReader = new BufferedReader(new FileReader("somepath")); 
     String line; 
     while ((line = bufferedReader.readLine()) != null) { 
      Object object = new Object(); 
      this.doSomething(object); 
     } 
     bufferedReader.close(); 
    } catch (FileNotFoundException e) { 
     e.printStackTrace(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
+1

我認爲這是更好地把一個try語句和多個接球要捕捉到的異常。更好的可讀性。 –

+0

在場景1中,你的意思是方法本身拋出IOException' – Vallentin

+0

@Vallentin'場景1'只是爲了控制,基本上忽略它。我只是想顯示沒有'try/catch'塊的代碼。 – prolink007

回答

13

您應根據以下標準範圍的嘗試/捕獲:

  • 做你需要做的基於不同的事情上在異常從來的?
  • 你需要根據做什麼不同的事情,哪個例外被拋出
  • 當拋出一個給定的異常時,需要跳過哪些代碼(又稱「無效」)?

回答這些問題將使您能夠確定任何try/catch塊的適當範圍。

+0

@Basilevs - 提及什麼具體關於築巢? – jtahlborn

+0

有些場景需要嵌套的try catch塊,我認爲小點可能會使這個答案更好。我可能是錯的 - 結構會被破壞。 – Basilevs

+0

@Basilevs - 嵌套的try/catch塊是一個實現選項,它與我上面提到的點相關。回答這些問題應該告訴你如何指定你的try/catch塊(單個/多個/嵌套/等)。 – jtahlborn

0

我認爲它與多少代碼放在方法相似。嘗試編寫try/catch/finally,最多隻能使用一個屏幕。我想說,將整個方法體封裝到try塊中並不是一個問題,但是如果它變得太長,你應該將這些代碼分成幾個方法。

0

你用一個try/catch的例子每個都沒有意義,因爲你只是打印一個堆棧跟蹤並繼續 - 已經知道這將是一個失敗。你也可以嘗試/捕獲整個事件,或者向方法簽名添加拋出SomeException異常,並讓調用方法決定哪裏出了問題。

另外,不要擔心在try/catch內擠得太多。您始終可以將該代碼提取到另一種方法中。可讀性是編程唯一最重要的方面之一。

0

第三種選擇當然是最好的。你不希望你的try/catch塊變得笨拙,但在這個例子中,它足夠短,你不需要像第二個選項那樣分割它。

5

我儘可能少的放在try-catch中。

這使您可以非常輕鬆地將代碼段移動到單獨的方法中,這是一種很好的編碼實踐(遵守單一責任原則;請參閱Robert C. Martin編寫的「Clean Code:敏捷軟件工匠手冊」一書)。

另一個優點是,您可以快速識別哪些代碼實際上可以拋出異常。

雖然方案2看起來有點極端,並且由於方法很小,方案3似乎是最佳選擇。

但是,您需要在finally塊中擁有「close」語句。

+0

我只是想創建一個例子。我沒有包括每個漁獲物的行爲,也沒有包括最後。只是試圖讓示例非常容易讓用戶瀏覽一下。不想讓信息超載。 – prolink007

+0

好的,這是有道理的 –

1

你應該去第三個場景。

如果緩衝讀取器遇到異常,然後在第二種情況下創建它,那麼它嘗試到readLine()就可以了,它會遇到另一個異常。爲同一個問題提出多個例外沒有意義。

你還應該在finally塊中關閉你的bufferedReader。

BufferedReader bufferedReader; 
try { 
    bufferedReader = new BufferedReader(new FileReader("somepath")); 
    String line; 
    while ((line = bufferedReader.readLine()) != null) { 
     Object object = new Object(); 
     this.doSomething(object); 
    } 
} catch (FileNotFoundException e) { 
    e.printStackTrace(); 
} catch (IOException e) { 
    e.printStackTrace(); 
} finally { 
    if (bufferedReader != null) 
     bufferedReader.close(); 
} 
+0

我只是想創建一個例子。我沒有包括每個漁獲物的行爲,也沒有包括最後。只是試圖讓示例非常容易讓用戶瀏覽一下。不想讓信息超載。 – prolink007

+0

另外,'close()'可以拋出。 –

0

不是情景2.如果的FileReader或BufferedReader類構造函數拋出,那麼的BufferedReader將是無效,但在未來的try/catch仍將執行。因此,你會在bufferedReader.readLine上得到一個(未捕獲的)異常 - 一個NullPointerException異常。在場景1和場景3之間,我通常更喜歡3個,因爲它不需要調用者捕捉。順便說一句,你不需要顯式捕獲FileNotFoundException,因爲它從IOException繼承,因此該catch塊將捕獲兩者。

0

我認爲一個Exception是一個uncoditionally返回結果類型。因此,當我使用try-catch部分時,我試圖回答問題

  1. 我應該在這裏處理意外的結果還是應該在更高級別上傳播它?
  2. 我應該處理哪些意外的結果?
  3. 如何處理它們?

在95%的情況下,我不會比第一點更進一步,所以我只是宣傳錯誤。

對於文件處理,我使用try-with-resources重新拋出IOExceptionthrow new RuntimeException(e)

2

這是一個意見。我已經看到了很多這些模式。

模式1只有當你的方法可以拋出異常並且具有調用者鏈處理的​​東西時纔是好的。這往往是渴望的。但是,由於close呼叫不在finally block中,因此可能無法呼叫。至少,使用try-finally塊。

模式2不好,因爲如果第一個try-catch塊處理異常,則該方法的其餘部分是無用的。

模式3是好的,但不是很好,因爲打印堆棧跟蹤隱藏了操作失敗的事實。如果調用者認爲該操作沒有發生,則該操作會發生什麼。此外,close可能沒有發生,這可能導致程序失敗。

在僞代碼,模式3的這個變體是更好:

Declare Streams, connections, etc. 
try 
    Initialize streams, connections, etc, 
    Do work. 
catch (optional) 
    Catch and handle exceptions. 
    Do not simply log and ignore. 
finally 
    Close connections and streams in reverse order. 
    Remember, closing these objects can throw, 
     so catch exceptions the close operation throws. 
End. 

如果您使用的是Java 7,使用try-與資源:

try (BufferedReader bufferedReader = new BufferedReader(new FileReader("somepath"))) { 
    String line; 
    while ((line = bufferedReader.readLine()) != null) { 
     Object object = new Object(); 
     this.doSomething(object); 
    } 
} 

IOException小號泡沫達呼叫者,召集者。

+0

我只是想創建一個例子。我沒有包括每個漁獲物的行爲,也沒有包括最後。只是試圖讓示例非常容易讓用戶瀏覽一下。不想讓信息超載。 – prolink007

0

jtahlborn已經有了正確的答案。

不幸的是,有時候,適當的異常處理可能會非常臃腫。 如果需要,應該準備好處理它。

另一種可能的情況是嵌套的try-catch塊。

考慮:

BufferedReader bufferedReader = new BufferedReader(new FileReader("somepath")); 
try { 
     String line; 

     while ((line = bufferedReader.readLine()) != null) { 
      Object object = new Object(); 
      try { 
       this.doSomething(object); 
      } catch (InvalidArgumentException iae) { 
       throw new RuntimeErrorException("Failed to process line " + line + ", iae); 
      } catch (ParserWarning e) { 
       e.printStackTrace(); 
      } 
     } 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } finally { 
     bufferedReader.close(); 
    } 
+0

是的,它很容易變得更加複雜。我只是想給一個簡單的例子,讓其他觀衆易於閱讀。 – prolink007