l

2011年5月27日 星期五

Exception Handling 必看 paper (1)

May 27 20:48~21:46

五月很忙,沒什麼時間搞笑,今天來介紹一篇 exception handling 的 paper,如果鄉民們想要深入研究或是了解 exception handling 的理論背景以便設計出好的例外處理程式,或是想要在不懂的人面前唬爛一番(就好像 Teddy 接下來要做的事情一樣...XD ),那麼這篇是值得一看的 paper。

相信只要是有在寫程式的鄉民們都會認同:例外處理是一件很困難的事情。為什麼?
  • 學校沒教:有誰在學校有學過如何設計出好的例外處理程式?大概就是在程式設計課程(例如 C++ 或 Java)的時候稍微提一下 exception 的概念,教一下 try, catch, finally, throw, throws 這幾個 keywords 的意義。如果還有時間的話,頂多再介紹一下 checked exception 與 unchecked exception 的差別。
  • 工作學不到:上班之後,光是忙著寫『正常功能』都來不及了,那還有時間去關注例外處理的問題?
  • 書上也沒寫:更慘的是,對於『有理想,有 報復 抱負』的鄉民們,就算是想要買本書來自修一下,也很難找到一本像樣的書介紹如何做例外處理設計。
就連跟著 Teddy 學了快兩年的學弟,到現在快畢業了也還是處於一知半解的狀況(路人甲內心獨白:是 Teddy 不會教吧!)。嗯嗯...想當年 Teddy 也是花了好一番功夫才學得這方面的一點皮毛,就利用這一系列的文章把當年看過幾篇關於 exception handling 方面的超優良 papers 介紹給鄉民『聞香』一下。今天先介紹『年資』最老的這一篇。
 
Exception Handling: Issues and a Proposed Notation, by John B. Goodenough, CACM, vol. 18, no. 12, Dec. 1975, pp. 683-696.

哇賽,這篇 30 幾年前的 paper 會不會過時了啊,還需要看嗎?雖然時間有點久遠,但是看完之後對於 exception 的定義以及 exception handling 的基礎概念會有很深入的了解。更棒的是,這篇 paper 可以在『這裡』下載,不必去訂閱什麼電子期刊才看的到。這一點對於已經出社會的鄉民們算是滿方便的(在台灣應該很少有公司會去訂 IEEE 或是 ACM 的電子期刊吧...)。

這篇 paper 有很多重點,在這邊講一個關於 『exception 用途 』的重點。什麼叫做『exception 用途』?就是說,在程式中我們會把 exception 拿來幹嗎。這問題不是很好笑嗎,exception 就是拿來代表『例外狀況』啊?No..No..No.. 並不全然如此,而且這樣的解釋有點『英翻中』的感覺,並沒有真正說明 exception 在程式語言中的用途。Exception 的用途可以分成三大類(別忘了,這些做研究的人最喜歡分類了...XD),failure, result classification 與 monitoring。

Failure
某個 method 或 function 無法達到其規格中所定義需要提供給客戶端(caller)的服務時,所丟出的例外。也就是說,如果一個 exception 代表著 failure 的含意,那麼就表示丟出這個 exception 的『人(method)』無法達成其被賦予的任務(講成白話文就是『小的辦事不力』...XD)。絕大多數的 exception 都是用來表示 failure,例如 Java 中的 IOException 與 NullPointerException。
 
Result classification
用來表示 the type of result being produced。意思是說,這樣的 exception 其實不是代表『錯誤發生』,而是類似『狀態變數』一樣,用來表示傳回值的種類(如何解讀這個傳回值的意義)。在原文中對於這一點著墨不多,以下為 Teddy 自行揣測的例子,如有錯誤請來函更正...XD。例如 Java 語言的 EOFException,依據 Java 文件的說明是用來表示『an end of file or end of stream has been reached unexpectedly during input』。當遇到 EOFException 的時候就表示檔案已經讀完了,剛剛讀出來的資料都是正確的,並不需要做什麼『例外處理』。此時只要把開啟的檔案關閉便可。

Monitoring
用來通知 caller 某種狀態發生了,直接看原文的說明比較快。

The invoker wants to be notified when some condition occurs. This is not because the condition indicates a failure or the type of result being produced. Rather it is because he simply wants to keep track of the computation's progress, or the operation may need additional information at certain points and it is too expensive to calculate this information every time the operation is invoked, sicne the conditions under which it is needed occur only rarely.

好,看不懂,沒關係,舉的例子。Java 的 InterruptedException 就是一種屬於 monitoring 這一類,看一下 Java 文件關於 InterruptedException 的說明:

Thrown when a thread is waiting, sleeping, or otherwise paused for a long time and another thread interrupts it using the interrupt method in class Thread.

InterruptedException 是要讓 caller (new 出該 thread 的人) 當該 thread 被『中斷』的時候能夠收到通知。為什麼要收到『thread 被中斷的通知』?因為如果某個 thread 睡了很久沒有醒過來(例如執行 wait, join 或是 sleep),但是你的主程式要準備結束了(或是想把沉睡的 小五郎 thread 喚醒請他走人),可是問題是你在主程式所 create 出來的 thread 還在睡覺啊,要如何喚醒他?此時可以呼叫 thread 的 interrupt method 來喚醒他,這樣,例如原本呼叫該 thread.sleep 的那個人就會收到一個 InterruptedException 。

Monitoring 這一類的使用方法在現在的程式語言中也很少了,當收到一個這種類型的 exception 時,caller 通常會選擇 terminate (離開閃人)或是 resume(繼續執行)。至於到底是要 terminate 或是 resume 就要看當時的狀況來決定。

***

講了這麼多,到底講對講錯 Teddy 都快搞迷糊了...XD。總之,基本上可以把 result classification 和 monitoring 的用法都視為是一種『notification』,所以 exception 的用法就可以簡化為 failure 與 notification 兩種。重點來了,一般所謂的 exception handling,指的是只有當 exception 是被當作  failure 的用法時,才需要考慮要如何來處理這個例外狀況。 如果 exception 是被當成 notification,由於實際上『並沒有錯誤發生』,所以沒有什麼錯誤要處理的。通常當 exception 是當作 notification (例如 EOFException 與 InterruptedException)使用的時候,都有固定的回應方法,此時只要用這些固定的方式來寫程式就好了。

好消息是,當作 notification 使用的情況並不多,Teddy 已經告訴鄉民們兩個 Java 的例子(EOFException 與 InterruptedException)。想當年 Teddy 還不懂這樣的觀念的時候,對於如何處理 InterruptedException 一直覺得很迷惑:明啊明是一個『例外』,但是卻什麼也沒處理,只要離開 thread 就好了。只要知道 InterruptedException 其實是把 exception 來拿當作 notification 使用這樣就不會覺的奇怪了。

壞消息是,絕絕絕大多數的 exception 都是當作 failure,既然是 failure,就表示有人辦事不力。既然有人辦事不力,就要 懲處 想辦法補救。至於如何補救,該由誰來補救,要怎樣才不會越補越大洞,這又是另一門學問了。講不完,有空再說。

***

友藏內心獨白:老 paper 也有春天...XD

2 則留言:

  1. 就是很難搞!

    一個底層的unchecked exception, 到底是要catch起來並且log呢? 還是要往上丟...

    catch起來在log中也許可以看見...但是UI看不到... 如果要往上丟交由callee去處理, 一個uncheck exception又不能完全限制所有callee處理... 改成checked exception又要改interface...

    回覆刪除
  2. 小弟打錯了, 是caller

    回覆刪除