當然,生成的違例必須在某個地方中止。這個“地方”便是違例控制器或者違例控制模塊。而且針對想捕獲的每種違例類型,都必須有一個相應的違例控制器。違例控制器緊接在try塊後面,且用catch(捕獲)關鍵字標記。如下所示:
try { // Code that might generate exceptions } catch(Type1 id1) { // Handle exceptions of Type1 } catch(Type2 id2) { // Handle exceptions of Type2 } catch(Type3 id3) { // Handle exceptions of Type3 } // etc...
每個catch從句——即違例控制器——都類似一個小型方法,它需要采用一個(而且只有一個)特定類型的自變量。可在控制器內部使用標識符(id1,id2等等),就象一個普通的方法自變量那樣。我們有時也根本不使用標識符,因為違例類型已提供了足夠的信息,可有效處理違例。但即使不用,標識符也必須就位。
控制器必須“緊接”在try塊後面。若“擲”出一個違例,違例控制機制就會搜尋自變量與違例類型相符的第一個控制器。隨後,它會進入那個catch從句,並認為違例已得到控制(一旦catch從句結束,對控制器的搜索也會停止)。只有相符的catch從句才會得到執行;它與switch語句不同,後者在每個case後都需要一個break命令,防止誤執行其他語句。
在try塊內部,請注意大量不同的方法調用可能生成相同的違例,但只需要一個控制器。
1. 中斷與恢復
在違例控制理論中,共存在兩種基本方法。在“中斷”方法中(Java和C++提供了對這種方法的支持),我們假定錯誤非常關鍵,沒有辦法返回違例發生的地方。無論誰只要“擲”出一個違例,就表明沒有辦法補救錯誤,而且也不希望再回來。
另一種方法叫作“恢復”。它意味著違例控制器有責任來糾正當前的狀況,然後取得出錯的方法,假定下一次會成功執行。若使用恢復,意味著在違例得到控制以後仍然想繼續執行。在這種情況下,我們的違例更象一個方法調用——我們用它在Java中設置各種各樣特殊的環境,產生類似於“恢復”的行為(換言之,此時不是“擲”出一個違例,而是調用一個用於解決問題的方法)。另外,也可以將自己的try塊置入一個while循環裡,用它不斷進入try塊,直到結果滿意時為止。
從歷史的角度看,若程序員使用的操作系統支持可恢復的違例控制,最終都會用到類似於中斷的代碼,並跳過恢復進程。所以盡管“恢復”表面上十分不錯,但在實際應用中卻顯得困難重重。其中決定性的原因可能是:我們的控制模塊必須隨時留意是否產生了違例,以及是否包含了由產生位置專用的代碼。這便使代碼很難編寫和維護——大型系統尤其如此,因為違例可能在多個位置產生。