充分發揮異常的優點,可以提高程序的可讀性、可靠性和可維護性。如果使用不當,它們會帶來負面影響。
1.只針對異常的情況才使用異常
以下這段代碼用拋出捕獲異常的方式來達到終止無線循環的目的。
tyr {
int i = 0;
while(true) {
range[i++].climb();
}
} catch (ArrayIndexOutOfBoundsException e) {
}
2.對可恢復的情況使用受檢異常,對編程錯誤使用運行時異常
Java 提供了三種可拋出結構(throwable):
- 受檢異常(checked exception)
- 運行時異常(runtime exception)
- 錯誤(error)
如果期望調用者能夠適當地恢復,對于這種情況使用受檢異常。強迫調用者在catch子句中處理該異常,或者將其傳播出去。
實現的所有未受檢的拋出結構都應該是 RuntimeException 的子類。
3.避免不必要地使用受檢的異常
過分使用受檢異常會使API使用起來非常不方便。因為不介意調用失敗而導致線程終于,所以可以重構為,把這個拋出異常分成兩個方法,其中一個方法是返回 boolean,表明是否應該拋出異常。
4.優先使用標準的異常
經常被重用的異常:
- IllegalArgumentException
- IllStateExcetption:如果因為接受對象的狀態而使調用非法,通常會拋出這個異常。例如,如果某個對象被正確初始化之前,調用者就企圖使用這個對象,就會拋出異常。
- NullPointerException
- IndexOutOfBoundsException
- ConcurrentModificationException:如果一個對象被設計為專門用于單線程或者與外部同步機制配合使用,一旦發現它正在被并發修改,就應該拋出異常
- UnsupportedOperationException:對象不支持所請求的操作,就拋出這個異常。
- ArithmeticException
- NumberFormatException
5.拋出與抽象相對應的異常
更高層的實現應該捕獲底層異常,同時拋出可以按照高層抽象進行解釋的異常。這種做法叫異常轉譯。
try {
} catch (LowerLevelException e) {
throw new HigherLevelException(..);
}
#### 6.每個方法拋出的異常都要有文檔
始終要單獨地聲明受檢的異常,并且利用 Javadoc 的 @throws 標記,準確地記錄下拋出每個異常的條件。
#### 7.在細節消息中包含能捕獲失敗的信息
當程序由于未被捕獲的異常而失敗的時候,系統會自動打印該異常的堆棧軌跡,在堆棧軌跡中包含該異常的字符串表示法,即 toString 方法,通常應該包含異常的類名,加細節消息,包括參數和域的信息。
#### 8.努力使失敗保持原子性
> 對于受檢異常,當對象拋出異常后,通常期望仍然保持一種定義良好的可用狀態,因為調用者其他能從這種異常中進行恢復,這種屬性稱為具有失敗原子性。
設計一個不可變的對象,對于可變對象,執行操作之前進行參數有效性檢查。
#### 9.不要忽略異常
空的catch塊會使異常達不到應有的目的。每當見到空catch塊,應該警鐘長鳴,至少,要包含一條說明,解釋為何可以忽略這個異常。