當(dāng)程序由于未捕獲的異常而失敗的時(shí)候筹淫,系統(tǒng)會(huì)自動(dòng)打印出該異常的堆棧軌跡想际。在堆棧軌跡中包含該異常的字符串表示法,即它的toString方法的調(diào)用結(jié)果怀估。它通常包含該異常的類(lèi)命狮鸭,緊隨其后的是細(xì)節(jié)消息(detailMessage)。通常多搀,這只是程序員或者網(wǎng)站可靠性工程師在調(diào)查軟件失敗原因時(shí)必須檢查的信息歧蕉。如果失敗的情形不容易重現(xiàn),要想獲得更多的信息會(huì)非常困難康铭,甚至是不可能惯退。因此,異常類(lèi)型的toString方法應(yīng)該盡可能多的返回有關(guān)失敗原因的信息从藤,這一點(diǎn)特別重要催跪。換句話(huà)說(shuō),異常的字符串表示法應(yīng)該捕獲失敗夷野,以便于后續(xù)進(jìn)行分析叠荠。
為了捕獲失敗,異常的細(xì)節(jié)信息應(yīng)該包含“對(duì)該異常有貢獻(xiàn)”的所有參數(shù)和域的值
扫责。例如,IndexOutOfBoundsException異常的細(xì)節(jié)消息應(yīng)該包含下界逃呼、上界以及沒(méi)有落在界內(nèi)的下標(biāo)值鳖孤。該細(xì)節(jié)消息提供了許多關(guān)于失敗的信息。這三個(gè)值任何一個(gè)或者全部都有可能是錯(cuò)的抡笼。實(shí)際的下標(biāo)值可能小于下界或者等于上界("越界錯(cuò)誤")苏揣,或者它可能是個(gè)無(wú)效值,太小或太大推姻。下界也有可能大于上界(嚴(yán)重違反內(nèi)部約束條件的一種情況)平匈。每一種情形都代表了不同的問(wèn)題,如果程序員知道應(yīng)該去查找哪些錯(cuò)誤藏古,就可以極大的加速診斷過(guò)程增炭。
對(duì)安全敏感的信息有一條忠告。由于在診斷和修正軟件問(wèn)題的過(guò)程中拧晕,許多人都可以看見(jiàn)堆棧軌跡隙姿,因此千萬(wàn)不要在細(xì)節(jié)消息中包含密碼、密鑰以及類(lèi)型的消息
厂捞!
雖然在異常的細(xì)節(jié)消息中包含所有相關(guān)的數(shù)據(jù)是非常重要的输玷,但是包含大量的描述信息往往沒(méi)有什么意義队丝。堆棧軌跡的用途是與源文件結(jié)合起來(lái)進(jìn)行分析,它通常拋出該異常的確切文件行數(shù)欲鹏,以及堆棧所有其他方法調(diào)用所在的文件和行數(shù)机久。關(guān)于失敗的冗長(zhǎng)描述信息通常是不必要的,這些信息可以通過(guò)閱讀源代碼而獲得赔嚎。
異常的細(xì)節(jié)消息不應(yīng)該與"用戶(hù)層次的錯(cuò)誤消息"混為一談膘盖,后者對(duì)于最終用戶(hù)而言必須是可理解的。與用戶(hù)層次的錯(cuò)誤消息不同尽狠,異常的字符串表示法主要是讓程序員或者網(wǎng)站可靠工程師用來(lái)分析失敗的原因衔憨。因此,信息的內(nèi)容比可讀性重要得多。用戶(hù)層次的錯(cuò)誤消息經(jīng)常被本地化建钥,而異常的細(xì)節(jié)消息則幾乎沒(méi)有被本地化朝聋。
為了確保在異常的細(xì)節(jié)消息中包含足夠的失敗-捕捉信息,一種辦法是在異常的構(gòu)造器而不是字符細(xì)節(jié)消息中引入這些信息码党。然后,有了這些信息斥黑,只要把它們放到消息描述中揖盘,就可以自動(dòng)產(chǎn)生細(xì)節(jié)消息。例如锌奴,IndexOutOfBoundsException使用如下構(gòu)造器代替String構(gòu)造器:
/**
* Constructs an IndexOutOfBoundsException.
*
* @param lowerBound the lowest legal index value
* @param upperBound the highest legal index value plus one
* @param index the actual index value
*/
public IndexOutOfBoundsException(int lowerBound, int upperBound,
int index) {
// Generate a detail message that captures the failure
super(String.format("Lower bound: %d, Upper bound: %d, Index: %d", lowerBound, upperBound, index));
// Save failure information for programmatic access
this.lowerBound = lowerBound;
this.upperBound = upperBound;
this.index = index;
}
從Java9開(kāi)始兽狭,IndexOutOfBoundsException終于獲得了一個(gè)構(gòu)造器,它可以帶一個(gè)類(lèi)型為int的index參數(shù)值鹿蜀,但遺憾的是箕慧,它刪除了lowerBound和upperBound參數(shù)。更通俗的說(shuō)茴恰,Java平臺(tái)類(lèi)庫(kù)并沒(méi)有廣泛的使用這種做法颠焦,但是,這種做法仍然值得大力推薦往枣。它使程序員更加易于拋出異常以捕獲失敗伐庭。實(shí)際上,這種做法使程序員不想捕獲異常都難分冈!這種做法可以有效的把代碼集中起來(lái)放在異常類(lèi)中圾另,由這些代碼對(duì)異常類(lèi)自身的異常產(chǎn)生高質(zhì)量的細(xì)節(jié)消息,而不是要求類(lèi)的每個(gè)用戶(hù)都多余的產(chǎn)生細(xì)節(jié)消息雕沉。
正如第70條中所建議的盯捌,為異常的失敗 - 捕獲信息(在上述例子中為lowerBound、upperBound和index)提供一些訪(fǎng)問(wèn)方法是合適的蘑秽。提供這樣的訪(fǎng)問(wèn)方法對(duì)受檢異常饺著,比對(duì)未受檢異常更為重要箫攀,因?yàn)槭?- 捕獲信息對(duì)于從失敗中恢復(fù)是非常有用的。程序員希望通過(guò)程序的手段來(lái)訪(fǎng)問(wèn)未受檢異常的細(xì)節(jié)幼衰,這很少見(jiàn)(盡管也可以想象)靴跛。然而,即使對(duì)未受檢異常渡嚣,作為一般原則提供這些訪(fǎng)問(wèn)方法也是明智的(詳見(jiàn)12條)梢睛。