如果方法拋出的異常與它所執(zhí)行的任務(wù)沒有明顯的聯(lián)系,這種情形將會使人不知所措煞肾。當(dāng)方法傳遞由底層抽象拋出的異常時咧织,往往會發(fā)生這種情況。除了使人感到困惑之外籍救,這也“污染”了具有實現(xiàn)細節(jié)的更高層的API拯爽。如果高層的實現(xiàn)在后續(xù)的發(fā)行版本中發(fā)生了變化,它所拋出的異常也可能會跟著發(fā)生變化钧忽,從而潛在的破壞現(xiàn)有的客戶端程序毯炮。
為了避免這個問題,更高層的實現(xiàn)應(yīng)該捕獲底層的異常耸黑,同時拋出可以按照高層抽象進行解析的異常
桃煎。這種做法稱為異常轉(zhuǎn)譯,如下代碼所示:
// Exception Translation
try {
... // Use lower-level abstraction to do our bidding
} catch (LowerLevelException e) {
throw new HigherLevelException(...);
}
下面的異常轉(zhuǎn)譯例子取自于AbstractSequentialList類型大刊,該類是List接口的一個骨架實現(xiàn)为迈,詳見第20條。在這個例子中,按照List<E>接口中的get方法的規(guī)范要求葫辐,異常轉(zhuǎn)譯是必需的:
/**
* Returns the element at the specified position in this list.
* @throws IndexOutOfBoundsException if the index is out of range
* ({@code index < 0 || index >= size()}).
*/
public E get(int index) {
ListIterator<E> i = listIterator(index);
try {
return i.next();
} catch (NoSuchElementException e) {
throw new IndexOutOfBoundsException("Index: " + index);
}
}
一種特殊的異常轉(zhuǎn)譯形式稱為異常鏈搜锰,如果底層的異常對于調(diào)試導(dǎo)致高層異常的問題非常有幫助,使用異常鏈就很合適耿战。低層的異常(原因)被傳到高層的異常蛋叼,高層的異常提供訪問方法(Throwable的getCause方法)來獲得低層的異常:
// Exception Chaining
try {
... // Use lower-level abstraction to do our bidding
} catch (LowerLevelException cause) {
throw new HigherLevelException(cause);
}
高層異常的構(gòu)造器將原因傳到支持鏈的超級構(gòu)造器,因此它最終將傳給Throwable的其中一個運行異常鏈的構(gòu)造器剂陡,例如Throwable(Throwable e):
// Exception with chaining-aware constructor
class HigherLevelException extends Exception {
HigherLevelException(Throwable cause) {
super(cause);
}
}
大多數(shù)標(biāo)準的異常都有支持鏈的構(gòu)造器狈涮。對于沒有支持鏈的異常,可以利用Throwable的initCause方法設(shè)置原因鸭栖。異常鏈不僅讓你可以通過程序(用getCause)訪問原因歌馍,還可以將原因的堆棧軌跡繼承到更高層的異常中。
盡管異常轉(zhuǎn)譯與不加選擇地從底層傳遞異常地做法相比有所改進晕鹊,但是也不能濫用它
松却。如有可能,處理來自低層異常地最好做法是溅话,在調(diào)用低層方法之前確保它們會成功執(zhí)行玻褪,從而避免它們拋出異常。有時候公荧,可以在給低層傳遞參數(shù)之前,檢查更高層方法參數(shù)地有效性同规,從而避免低層方法拋出異常循狰。
如果無法阻止來自低層的異常,其次的做法是券勺,讓更高層來悄悄地處理這個異常绪钥,從而將高層方法的調(diào)用者與低層地問題隔離開來。在這種情況下关炼,可以用某種適當(dāng)?shù)挠涗洐C制(如java.util.logging)將異常記錄下來程腹。這有助于管理員調(diào)查問題,同時又將客戶端代碼和最終用戶與問題隔離開來儒拂。
總而言之寸潦,如果不阻止或者處理來自更低層的異常,一般的做法是使用異常轉(zhuǎn)譯社痛,只有在低層方法的規(guī)范碰巧可以保證它所拋出的所有異常對于更高層也是合適的情況下见转,才可以將異常從低層傳播到高層。異常鏈對高層和低層異常都提供了最佳的功能:它允許拋出適當(dāng)?shù)母邔赢惓K獍В瑫r又能捕獲低層的原因進行失敗分析(詳見第75條)斩箫。