Apr. 29 10:18~12:26
上禮拜六、日Teddy抽出一些時間整理「例外處理設計與重構實作班」的教材,整理好100頁左右的投影片,大概是課程一半的內容。在整理過程中Teddy突然想到一則小故事…
***
話說N年前有一天Teddy在電視上看到李敖先生參加某個節目接受訪問,在受訪的過程中,李敖先生說了大意如下的一句話:「每個人都會罵王八蛋,但我李敖可以證明你是王八蛋」。
***
要罵人是王八蛋很簡單,但是要「證明」一個人是王八蛋就要靠收集資料的功夫了,可不能像有些名嘴不做功課,光靠打打嘴砲就可以打混過去的。
看到這裡鄉民們又會想:「這和例外處理何干」?有寫過程式的鄉民們大該都會同意,例外處理是一件很困難的工作。但是,有沒有人想過,為什麼例外處理會這麼難、到底難在何處?唯有先分析問題,才有機會找出合適的解決方案。
Teddy內心獨白:每個人都說例外處理很難,但只有Teddy可以說明為什麼例外處理很難。
***
其實說破了道理也很簡單:因為「例外處理」牽扯到好幾個相關但卻不相同的觀點或是面向,例外處理要做得好,這些觀點都必須要被關注到。Teddy認為例外處理至少涵蓋了以下五個觀點,這一集先談一下例外用途觀點。
- Usage View(用途觀點)
- Design View(設計觀點)
- Handling View(處理觀點)
- Tool-Support View(工具支援觀點)
- Process View(流程觀點)
***
Usage View(用途觀點)
例外不就是例外嗎,還能有什麼其他用途?如果鄉民們這樣想就弱掉了。雖然理論上例外是用來表示failure(請參考《Fault、Error、Failure、Exception》這一篇),但是事實上例外還有可能被用來當作result classification與monitoring。當例外被當作result classification與monitoring時,並不是一種異常狀況,而是用來表達一種狀態通知,因此通常不需要加以特別處理。
以上翻成白話文就是說:「寫程式遇到別人丟出例外時,請先判斷這個例外是用來但表failure,還是用來表示狀態通知(result classification與monitoring)」。看一個例子就知道:請問Java語言裡面的InterruptedException要如何處理?
這個問題N年前當Teddy第一次用Java寫多執行緒程式的時候,也是困擾了很久。InterruptedException明啊明是一個例外,可是為什麼捕捉之後卻沒有特別處理?經過N年之後,Teddy陰錯陽差投入例外處理研究之後才慢慢弄清楚,原來InterruptedException在這裡(上圖中的程式範例)並不是用來表達failure(某人辦事不力),而只是一種狀態通知,用來告訴等待或是執行中的執行緒有其他人把你給中斷了,請識相一點不要硬撐準備拍拍屁股可以做完收工了。這也是為什麼上面這個例子在捕捉到InterruptedException之後什麼都沒做的原因,在這裡如果硬要設計什麼「例外處理程式碼」,想要「拯救」被中斷的執行緒,反倒很有可能造成程式錯誤。
***
以上內容如果鄉民們能夠理解,恭喜您踏入了例外處理設計的大門。但是世間的事情如果都那麼簡單,黑白分明,事情就好辦了。要特別將「例外用途」提出來當成一個觀點來討論的原因,就是因為鄉民們通常無法直接透過例外物件本身來判斷這個例外是屬於哪種用途,而必須還要搭配application context來決定(由caller決定)。
舉個例子,假設鄉民們正在開發藍光光碟撥放器軟體,這個軟體有一個自我測試的功能,用來判斷使用者的電腦夠不夠力播放高畫質藍光電影。在自我測試模式,應用程式如果持續接收到frame遺失例外,此時這個例外應該要被當成failure(電腦系統不夠力),並且將這個情況回報給使用者知道(錯誤處理)。
但是,當播放軟體處於正常模式,正在播放電影時若發生了frame遺失例外,此時就應該把這個例外當成是一種狀態通知,直接忽略不須回報給使用者(頂多log起來)。否則使用者在看電影的時候不是會一直被中斷,強迫按下「確定」或「取消」按鈕才可以繼續。這樣的播放軟體應該沒有人會想要使用吧。
***
每次寫例外處理的文章都要花特別久的時間,解釋完第一個觀點,還有其他四個下集待續。
***
友藏內心獨白:沒意外的話例外處理這門課今年7月6~7日應該是會開了。