l

2013年11月25日 星期一

Java的try、catch、finally(8):例外處理失敗怎麼辦?

Nov. 18 16:35~17:35

image

上禮拜六「第二梯次例外處理設計與重構實作班」課程中,有一位學員問了Teddy一個問題…

學員:你上課的時候提到catch block的責任之一是負責「錯誤處理(error-handling)」,也就是說如果系統狀態不對了,要想辦法將系統恢復到一個正確的狀態。

Teddy:對啊。

學員:我們之前有遇到一個錯誤處理的問題,團隊成員和主管討論了很久都沒有結論。

Teddy:什麼問題?

學員:如果錯誤處理的程式也發生錯誤,那該怎麼辦?

Teddy:很簡單,三秒鐘就可以回答你。如果錯誤處理的程式也發生錯誤,無法將系統回復到正確的狀態,就丟出一個ErrorHandlingException來代表這樣的異常狀況。

***

上述問題可以用下列例子來思考。有遊客在海邊溺水發出求救訊號(丟出例外),這時候「救生員」(例外處理程式)要去搶救這位溺水的遊客。如果救生員搶救失敗,自己也溺水了,那怎麼辦?

  1. 假裝什麼事都沒發生,把求救訊號(例外)吃掉。
  2. 繼續向外發出求救訊號。

現在答案就很明顯,應該是要選2,繼續向外發出求救訊號。但是接下來還是有一個問題需要考慮,那就是例外蓋台的問題:

  • 如果救生員直接發出ErrorHandlingException,那麼這個例外會覆蓋掉原本遊客溺水的例外,產生「例外蓋台」的問題。

所以說,這個ErrorHandlingException應該成為一個suppressed exception,被加入到原本遊客溺水的例外身上(代表遊客溺水的例外在這裡稱為function failure

***

下圖說明了當例外處理失敗(包含cleanup失敗)的時候要如何處理的作法。

image

 

簡而言之,鄉民們需要:

  • 自己定義ErrorHandlingException、FaultHandlingException、CleanupException、這三種runtime exception。
  • 如果catch block需要做error-handling或是fault-handling的工作但卻失敗了,則產生ErrorHandlingException、FaultHandlingException來表示這種例外狀況。
  • 如果finally block需要做cleanup的工作但卻失敗了,則產生CleanupException來表示這種例外狀況。

寫到這裡鄉民們可能會想:「丟出了ErrorHandlingException、FaultHandlingException、CleanupException難道就沒事了嗎?要不要在caller的程式碼中去處理這些例外?」

這個問題要看鄉民們對於程式強健度的要求有多高,以及這些例外產生的機率。雖然「理論上」程式運行的時候有可能會發生ErrorHandlingException、FaultHandlingException、CleanupException,但「實際上」這些例外發生的機率與頻率有多高,有時候在設計階段並不容易預測。如果針對每一個function或是method都要去思考要如何處理它們「可能」會丟出來的所有例外,那麼可能會造成不必要的過度設計,浪費太多資源。在這種情況下,開發人員只要確定:

  1. 所有的例外狀況都有被回報。
  2. 回報語意清楚的例外,以便協助開發團隊縮短事後除錯時間。

這樣的例外處理策略就可以應付大部分的情況,也可以避免過早且過度設計例外處理方法的問題。

***

友藏內心獨白:例外處理的例外,還是例外。

1 則留言: