當程序由于未被捕獲的異常而失敗的時候,系統(tǒng)會自動地打印出該異常的堆棧軌跡隅俘。在堆棧軌跡中包含該異常的字符串表示法(string representation)邻奠,即它的toString方法的調用結果。它通常包含該異常的類名为居,緊隨其后的是細節(jié)消息(detail message)碌宴。通常,這只是程序員或者域服務人員(field service personnel蒙畴,指檢查軟件失敗的人)在調查軟件失敗原因時必須檢查的信息贰镣。如果失敗的情形不容易重現,要想獲得更多的信息會非常困難忍抽,甚至是不可能的八孝。因此,異常類型的toString方法應該盡可能多地返回有關失敗原因的信息鸠项,這一點特別重要。換句話說子姜,異常的細節(jié)消息應該捕獲住失敗祟绊,便于以后分析楼入。
為了捕獲失敗,異常的細節(jié)信息應該包含所有“對該異常有貢獻”的參數和域的值牧抽。例如嘉熊,IndexOutOfBoundsException異常的細節(jié)消息應該包含下界、上界以及沒有落在界內的下標值扬舒。該細節(jié)消息提供了許多關于失敗的信息阐肤。這三個值中任何一個或者全部都有可能是錯的。實標的下標值可能小于下界或等于上界(“越界錯誤”)讲坎,或者它可能是個無效值孕惜,太小或太大。下界也有可能大于上界(嚴重違反內部約束條件的一種情況)晨炕。每一種情形都代表了不同的問題衫画,如果程序員知道應該去查找哪種錯誤,就可以極大地加速診斷過程瓮栗。
雖然在異常的細節(jié)消息中包含所有相關的“硬數據(hard data)”是非常重要的削罩,但是包含大量的描述信息往往沒有什么意義。堆棧軌跡的用途是與源文件結合起來進行分析费奸,它通常包含拋出該異常的確切文件和行數弥激,以及堆棧中所有其他方法調用所在的文件和行數。關于失敗的冗長描述信息通常是不必要的愿阐,這些信息可以通過閱讀源代碼而獲得秆撮。
異常的細節(jié)消息不應該與“用戶層次的錯誤消息”混為一談,后者對于最終用戶而言必須是可理解的换况。與用戶層次的錯誤消息不同职辨,異常的字符串表示法主要是讓程序員或者域服務人員用來分析失敗的原因。因此戈二,信息的內容比可理解性要重要得多舒裤。
為了確保在異常的細節(jié)消息中包含足夠的能捕獲失敗的信息,一種辦法是在異常的構造器而不是字符串細節(jié)消息中引入這些信息觉吭。然后腾供,有了這些信息,只要把它們放到消息描述中鲜滩,就可以自動產生細節(jié)消息伴鳖。例如IndexOutOfBoundsException并不是有個String構造器,而是有個這樣的構造器:
public class IndexOutOfBoundsException {
public IndexOutOfBoundsException(int lowerBound, int upperBound, int index) {
super("Lower bound:" + lowerBound +
",Upper bound:" + upperBound +
",Index:" + index);
this.lowerBound = lowerBound;
this.upperBound = upperBound;
this.index = index;
}
}
遺憾的是徙硅,Java平臺類庫并沒有廣泛地使用這種做法榜聂,但是,這種做法仍然值得大力推薦嗓蘑。它使程序員更加易于拋出異常以捕獲失敗须肆。實際上匿乃,這種做法使程序員不想捕獲失敗都難!這種做法可以有效地把代碼集中起來放在異常類中豌汇,由這些代碼對異常類自身中的異常產生高質量的細節(jié)消息幢炸,而不是要求類的每個用戶都多余地產生細節(jié)消息。
正如第58條中所建議的拒贱,為異常的“失敗捕獲”信息提供一些訪問方法是合適的(在上述例子中的lowerBound宛徊、upperBound和index方法)提供一些訪問方法是合適的。提供這樣的訪問方法對于受檢的異常逻澳,比對于未受檢的異常更為重要闸天,因為失敗——捕獲信息對于從失敗中恢復是非常有用的。