1. 什麼是例外?
  2. 如果沒有例外?
  3. 結語

 

最早接觸到例外 (Exception) 機制是因為碰 Java

其實教科書上面講的範例並不是很深 

try {
    if (condition)
        throw new Exception("Message");
    // Code to Execute
} catch (Exception e){
    // Exception Handling
}

那時候聽到來補修的學長說了一句

「這跟直接用 if ... else 有什麼不一樣?」

對啊,剛接觸的筆者也這樣想

有什麼不一樣?


首先想想「什麼叫做例外?」

例外字面上意義很明顯,就是例外的狀況

對象很重要,對於什麼來說算是例外的狀況?

我們知道,對於一個程式單體而言

內部是分工合作的

組織架構就是完完全全的上對下專制命令關係

從物件觀點,當在 A 模組內

寫下執行 B 模組功能的指令時

代表 A 命令 B 去做某件事情

(這是題外話) 不能隨便顛倒或者交互使用的

一旦如此,組織間就會相互牽扯

結構會變得繁雜難維護

如果程式有一定的規模,最好不要設計這種程式結構

最簡潔的就是只有鄰近上下層關係的階層式結構 

 

在一層層分工的狀態下

總有一個領導者,指導下一層級各自獨立的工作人員的作業程序

工作人員接收指令,執行相對應工作

回傳或不回傳產出報告給上一層的領導者

萬一遇到可能會出錯的狀況怎麼辦?

端看這個錯誤後續處理工作究竟是不是屬於這個工作人員份內的事

若是份內的事,由這個工作人員自行吸收解決或者忽略便可

以程式碼來寫就是

if (is error condition)
    Do Error Handling myself

若錯誤不應該是這個工作人員的處理範圍

對於這個工作人員來說,這就是例外狀況

應該要中斷工作回報給上級,由上級決定怎麼處理

階層式的結構下,上級同時扮演著工作人員的角色

當這個例外狀況,對於它來說也是例外狀況

不應該由它來決定如何處理時

就必須再繼續回報給更上級的人員處理

因此,例外狀況是有可能一直往上傳遞的

例外處理的概念約是如此


有人會問為什麼要有這種用 if else就可以取代的機制?

那就該反問,如果不靠例外機制,身為開發者要怎麼解決例外問題

以現有的機制存在什麼技術上的困難?

很簡單不是嗎? 靠 return 回報給上級就好啦

所以寫下

if ( is exception condition )
    return ERROR

可前面有說過,工作人員有分需要寫工作報告或不要寫工作報告的兩種

如果這個工作人員是需要寫工作報告的

這樣的機制下要達成例外處理,上級必須要有辦法知道

錯誤報告和正常工作報告有什麼不一樣時才成立

我們以 Java 計算移動距離的例子來說

// velocity can be positive or negative
// time must be positive
int distance(int velocity, int time){
   if (time < 0)
      RETURN WHAT?????
}

 以上計算距離的例子,回傳值把整數能表示的範圍全占了

上層應該要以什麼標準來判斷什麼是例外狀況?

並且錯誤狀況也是有分種類的

依照不同的錯誤,也必須要給予不同的錯誤處理

如果能夠表達種類的空間不夠時,又該怎麼辦呢?


喔!

就用 global 的方式來設定錯誤狀況

例如像 C 標準底下所提供的 errno

有一個專門用來儲存錯誤狀況的標記空間,很好嘛!

空間也很大喔

範例:

// for lower-level
void worker(){
    if ( is exception condition A ){
        errno = A_TYPE_ERROR;
        return;
    }

    if ( is exception condition B ){
        errno = B_TYPE_ERROR;
        return;
    }
}

// for higher level
void commander(){

    worker();
    if ( error == A_TYPE_ERROR )
        Do A Type Error Handling

    if ( error == B_TYPE_ERROR ) // is exception
        return;
}

 

問題來了,前面提到錯誤狀況是要分種類的

從上面的例子也可以看到

但是,種類不只要依性質分類,還要依功能來分類

不同功能下,同性質的錯誤是可能要用不同的錯誤處理機制的

那有什麼關係?錯誤碼分開不就好了?

好,試問一支程式裡面有沒有可能使用第三方所開發的模組函式呢?

能夠保證所有人定義的錯誤碼不會衝突打架嗎?

喔~那全世界的所有程式開發者就應該集中起來開個會

規定說 errno 裡面哪個 range 我要了,其他人不能動

可能嗎?就算可能好了

知道嗎?IPv4 的 IP 已經不夠用了

也不是所有計算裝置都能和需要支援IPv6

 

笨欸!那錯誤碼儲存的變數分開設置就好啦

相同的問題,能夠保證每個人定義出來的名稱都不一樣?

所以很顯然,global變數的方式也有它的瓶頸

 

不知道讀者看到現在有沒有發現

如果繼續使用 if 與 return 的方式一層層傳遞

每一層都必須對所有可能回傳的錯誤種類做判斷

真要這樣寫程式的話

不管你累不累,反正我是累了


那好吧,下層工作人員知道自己的主管是哪位行了吧

所以程式碼就要變成

commander(){

    caller = this function;
    worker();
}

worker(){

    if (is error condition)
        Let Caller Handle Error
}

以上的程式碼,不管是用程序導向方式或者是物件導向方式來設計

都有一定的困難度

1. 函式呼叫有堆疊 (stack) 來保持每次呼叫的獨立性
    不能用一個 global 的變數來儲存
    ( 但是可以自己建立一個 global的堆疊呀!) 

2. 同一個工作人員,可能被多個指揮人員叫用
    ( 有 global 堆疊怕什麼!)

3. global 堆疊,必須全世界所有模組共用同一個名稱
    ( 全世界的人集中開會好商量!)

4. 每次命令執行之前,都要設定一次指揮人員是誰
    這個設定必須由指揮者設定
    ( 麻煩而已,我行!)

5. 指揮者都必須要有固定名稱的錯誤處理提供呼叫
    ( 麻煩點而已嘛,全世界的人集中開會都好商量呀!)

6. 函式不管是正常結束或錯誤結束前必須解除指揮者
    這個設定可以由指揮者設定,也可以由工作者自己解除
    ( OK呀!)

7. 函式在一個執行鏈當中被多次呼叫,甚至是遞回呼叫
    函式怎麼知道自己現在在第幾層?
    ( 看堆疊最後一個呼叫者是誰就好啦!)

8. 如果遞回呼叫指揮者是自己,這個錯誤該或不該被處理?
    又要怎麼和指揮者不是自己的情況下區分?

9. 下級命令上級作事,這是極嚴重的越權行為
    也會產生模組間的不必要連結

 

總而言之,雖然上面提到的問題都好像有解決辦法

雖然一半以上不太可行,卻也有無解的問題

當然問題 9 可以用回調 (callback) 來解決

切斷下級「直接」命令上級做事的惡緣

不過基本上也有上述提到的問題

包含每層間都必須設定、錯誤代碼定義衝突

每層都必須檢查錯誤碼等


因為筆者只想得到那麼多解法

而且都有一定程度的問題不能只靠這些機制解決

自然一套能夠跳脫現有框架的機制

在語言層級上要被設計出來

例外機制有

  • 不受回傳值範圍控制
  • 自動向上傳遞
  • 僅與目前的執行鏈有關
  • 能夠分門別類定義錯誤機制
  • 指揮者不需要每每檢查所有可能的錯誤
    僅需處理自身需要負責的錯誤責任即可
    (應說,開發人員不需要寫那麼多)

基本上能夠解掉上面所提到的問題

如何實作這樣的機制,筆者沒有去研究

當然例外機制,也有使用上一些麻煩、不好處理的地方

等到日後再說吧

創作者介紹
創作者 wylokgo101 的頭像
wylokgo101

豆棚瓜架雨如絲 - WYLOKGO101

wylokgo101 發表在 痞客邦 留言(0) 人氣()