六種異常處理的陋習(xí)
你覺得自己是一個(gè)Java專家嗎衷旅?是否肯定自己已經(jīng)全面掌握了Java的異常處理機(jī)制塞弊?在下面這段代碼中澜术,你能夠迅速找出異常處理的六個(gè)問題嗎?
1 OutputStreamWriter out = ...
2 java.sql.Connection conn = ...
3 try { // ⑸
4 Statement stat = conn.createStatement();
5 ResultSet rs = stat.executeQuery(
6 "select uid, name from user");
7 while (rs.next())
8 {
9 out.println("ID:" + rs.getString("uid") // ⑹
10 "腿准,姓名:" + rs.getString("name"));
11 }
12 conn.close(); // ⑶
13 out.close();
14 }
15 catch(Exception ex) // ⑵
16 {
17 ex.printStackTrace(); //⑴,⑷
18 }
作為一個(gè)Java程序員拾碌,你至少應(yīng)該能夠找出兩個(gè)問題吐葱。但是,如果你不能找出全部六個(gè)問題校翔,請(qǐng)繼續(xù)閱讀本文弟跑。
本文討論的不是Java異常處理的一般性原則,因?yàn)檫@些原則已經(jīng)被大多數(shù)人熟知防症。我們要做的是分析各種可稱為“反例”(anti-pattern)的違背優(yōu)秀編碼規(guī)范的常見壞習(xí)慣孟辑,幫助讀者熟悉這些典型的反面例子,從而能夠在實(shí)際工作中敏銳地察覺和避免這些問題蔫敲。
反例之一:丟棄異常
代碼:15行-18行饲嗽。
這段代碼捕獲了異常卻不作任何處理,可以算得上Java編程中的殺手奈嘿。從問題出現(xiàn)的頻繁程度和禍害程度來看貌虾,它也許可以和C/C++程序的一個(gè)惡名遠(yuǎn)播的問題相提并論??不檢查緩沖區(qū)是否已滿。如果你看到了這種丟棄(而不是拋出)異常的情況裙犹,可以百分之九十九地肯定代碼存在問題(在極少數(shù)情況下尽狠,這段代碼有存在的理由衔憨,但最好加上完整的注釋,以免引起別人誤解)晚唇。
這段代碼的錯(cuò)誤在于巫财,異常(幾乎)總是意味著某些事情不對(duì)勁了,或者說至少發(fā)生了某些不尋常的事情哩陕,我們不應(yīng)該對(duì)程序發(fā)出的求救信號(hào)保持沉默和無動(dòng)于衷平项。調(diào)用一下printStackTrace算不上“處理異常”悍及。不錯(cuò)闽瓢,調(diào)用printStackTrace對(duì)調(diào)試程序有幫助,但程序調(diào)試階段結(jié)束之后心赶,printStackTrace就不應(yīng)再在異常處理模塊中擔(dān)負(fù)主要責(zé)任了扣讼。
丟棄異常的情形非常普遍。打開JDK的ThreadDeath類的文檔缨叫,可以看到下面這段說明:“特別地椭符,雖然出現(xiàn)ThreadDeath是一種‘正常的情形’,但ThreadDeath類是Error而不是Exception的子類耻姥,因?yàn)樵S多應(yīng)用會(huì)捕獲所有的Exception然后丟棄它不再理睬销钝。”這段話的意思是琐簇,雖然ThreadDeath代表的是一種普通的問題蒸健,但鑒于許多應(yīng)用會(huì)試圖捕獲所有異常然后不予以適當(dāng)?shù)奶幚恚訨DK把ThreadDeath定義成了Error的子類婉商,因?yàn)镋rror類代表的是一般的應(yīng)用不應(yīng)該去捕獲的嚴(yán)重問題似忧。可見丈秩,丟棄異常這一壞習(xí)慣是如此常見盯捌,它甚至已經(jīng)影響到了Java本身的設(shè)計(jì)。
那么蘑秽,應(yīng)該怎樣改正呢挽唉?主要有四個(gè)選擇:
1、處理異常筷狼。針對(duì)該異常采取一些行動(dòng)瓶籽,例如修正問題、提醒某個(gè)人或進(jìn)行其他一些處理埂材,要根據(jù)具體的情形確定應(yīng)該采取的動(dòng)作塑顺。再次說明,調(diào)用printStackTrace算不上已經(jīng)“處理好了異常”严拒。
2扬绪、重新拋出異常。處理異常的代碼在分析異常之后裤唠,認(rèn)為自己不能處理它挤牛,重新拋出異常也不失為一種選擇。
3种蘸、把該異常轉(zhuǎn)換成另一種異常墓赴。大多數(shù)情況下,這是指把一個(gè)低級(jí)的異常轉(zhuǎn)換成應(yīng)用級(jí)的異常(其含義更容易被用戶了解的異常)航瞭。
4诫硕、不要捕獲異常。
結(jié)論一:既然捕獲了異常刊侯,就要對(duì)它進(jìn)行適當(dāng)?shù)奶幚碚掳臁2灰东@異常之后又把它丟棄,不予理睬滨彻。
反例之二:不指定具體的異常
代碼:15行藕届。
許多時(shí)候人們會(huì)被這樣一種“美妙的”想法吸引:用一個(gè)catch語句捕獲所有的異常。最常見的情形就是使用catch(Exception ex)語句亭饵。但實(shí)際上翰舌,在絕大多數(shù)情況下,這種做法不值得提倡冬骚。為什么呢?
要理解其原因,我們必須回顧一下catch語句的用途。catch語句表示我們預(yù)期會(huì)出現(xiàn)某種異常愈腾,而且希望能夠處理該異常壮莹。異常類的作用就是告訴Java編譯器我們想要處理的是哪一種異常。由于絕大多數(shù)異常都直接或間接從java.lang.Exception派生现横,catch(Exception ex)就相當(dāng)于說我們想要處理幾乎所有的異常。
再來看看前面的代碼例子。我們真正想要捕獲的異常是什么呢舍悯?最明顯的一個(gè)是SQLException,這是JDBC操作中常見的異常睡雇。另一個(gè)可能的異常是IOException萌衬,因?yàn)樗僮鱋utputStreamWriter。顯然它抱,在同一個(gè)catch塊中處理這兩種截然不同的異常是不合適的秕豫。如果用兩個(gè)catch塊分別捕獲SQLException和IOException就要好多了。這就是說,catch語句應(yīng)當(dāng)盡量指定具體的異常類型混移,而不應(yīng)該指定涵蓋范圍太廣的Exception類祠墅。
另一方面,除了這兩個(gè)特定的異常歌径,還有其他許多異常也可能出現(xiàn)毁嗦。例如,如果由于某種原因回铛,executeQuery返回了null狗准,該怎么辦?答案是讓它們繼續(xù)拋出勺届,即不必捕獲也不必處理驶俊。實(shí)際上,我們不能也不應(yīng)該去捕獲可能出現(xiàn)的所有異常免姿,程序的其他地方還有捕獲異常的機(jī)會(huì)??直至最后由JVM處理饼酿。
結(jié)論二:在catch語句中盡可能指定具體的異常類型,必要時(shí)使用多個(gè)catch胚膊。不要試圖處理所有可能出現(xiàn)的異常故俐。
反例之三:占用資源不釋放
代碼:3行-14行。
異常改變了程序正常的執(zhí)行流程紊婉。這個(gè)道理雖然簡(jiǎn)單药版,卻常常被人們忽視。如果程序用到了文件喻犁、Socket槽片、JDBC連接之類的資源,即使遇到了異常肢础,也要正確釋放占用的資源还栓。為此,Java提供了一個(gè)簡(jiǎn)化這類操作的關(guān)鍵詞finally传轰。
finally是樣好東西:不管是否出現(xiàn)了異常剩盒,F(xiàn)inally保證在try/catch/finally塊結(jié)束之前,執(zhí)行清理任務(wù)的代碼總是有機(jī)會(huì)執(zhí)行慨蛙。遺憾的是有些人卻不習(xí)慣使用finally辽聊。
當(dāng)然,編寫finally塊應(yīng)當(dāng)多加小心期贫,特別是要注意在finally塊之內(nèi)拋出的異常??這是執(zhí)行清理任務(wù)的最后機(jī)會(huì)跟匆,盡量不要再有難以處理的錯(cuò)誤。
結(jié)論三:保證所有資源都被正確釋放通砍。充分運(yùn)用finally關(guān)鍵詞贾铝。
反例之四:不說明異常的詳細(xì)信息
代碼:3行-18行。
仔細(xì)觀察這段代碼:如果循環(huán)內(nèi)部出現(xiàn)了異常,會(huì)發(fā)生什么事情垢揩?我們可以得到足夠的信息判斷循環(huán)內(nèi)部出錯(cuò)的原因嗎玖绿?不能。我們只能知道當(dāng)前正在處理的類發(fā)生了某種錯(cuò)誤叁巨,但卻不能獲得任何信息判斷導(dǎo)致當(dāng)前錯(cuò)誤的原因斑匪。
printStackTrace的堆棧跟蹤功能顯示出程序運(yùn)行到當(dāng)前類的執(zhí)行流程,但只提供了一些最基本的信息锋勺,未能說明實(shí)際導(dǎo)致錯(cuò)誤的原因蚀瘸,同時(shí)也不易解讀。
因此庶橱,在出現(xiàn)異常時(shí)贮勃,最好能夠提供一些文字信息,例如當(dāng)前正在執(zhí)行的類苏章、方法和其他狀態(tài)信息寂嘉,包括以一種更適合閱讀的方式整理和組織printStackTrace提供的信息。
結(jié)論四:在異常處理模塊中提供適量的錯(cuò)誤原因信息枫绅,組織錯(cuò)誤信息使其易于理解和閱讀泉孩。
反例之五:過于龐大的try塊
代碼:3行-14行。
經(jīng)巢⒘埽可以看到有人把大量的代碼放入單個(gè)try塊寓搬,實(shí)際上這不是好習(xí)慣。這種現(xiàn)象之所以常見县耽,原因就在于有些人圖省事句喷,不愿花時(shí)間分析一大塊代碼中哪幾行代碼會(huì)拋出異常、異常的具體類型是什么兔毙。把大量的語句裝入單個(gè)巨大的try塊就象是出門旅游時(shí)把所有日常用品塞入一個(gè)大箱子唾琼,雖然東西是帶上了,但要找出來可不容易瞒御。
一些新手常常把大量的代碼放入單個(gè)try塊,然后再在catch語句中聲明Exception神郊,而不是分離各個(gè)可能出現(xiàn)異常的段落并分別捕獲其異常肴裙。這種做法為分析程序拋出異常的原因帶來了困難,因?yàn)橐淮蠖未a中有太多的地方可能拋出Exception涌乳。
結(jié)論五:盡量減小try塊的體積蜻懦。
反例之六:輸出數(shù)據(jù)不完整
代碼:7行-11行。
不完整的數(shù)據(jù)是Java程序的隱形殺手夕晓。仔細(xì)觀察這段代碼宛乃,考慮一下如果循環(huán)的中間拋出了異常,會(huì)發(fā)生什么事情。循環(huán)的執(zhí)行當(dāng)然是要被打斷的征炼,其次析既,catch塊會(huì)執(zhí)行??就這些,再也沒有其他動(dòng)作了谆奥。已經(jīng)輸出的數(shù)據(jù)怎么辦眼坏?使用這些數(shù)據(jù)的人或設(shè)備將收到一份不完整的(因而也是錯(cuò)誤的)數(shù)據(jù),卻得不到任何有關(guān)這份數(shù)據(jù)是否完整的提示酸些。對(duì)于有些系統(tǒng)來說宰译,數(shù)據(jù)不完整可能比系統(tǒng)停止運(yùn)行帶來更大的損失。
較為理想的處置辦法是向輸出設(shè)備寫一些信息魄懂,聲明數(shù)據(jù)的不完整性沿侈;另一種可能有效的辦法是,先緩沖要輸出的數(shù)據(jù)市栗,準(zhǔn)備好全部數(shù)據(jù)之后再一次性輸出缀拭。
結(jié)論六:全面考慮可能出現(xiàn)的異常以及這些異常對(duì)執(zhí)行流程的影響。
改寫后的代碼
根據(jù)上面的討論肃廓,下面給出改寫后的代碼智厌。也許有人會(huì)說它稍微有點(diǎn)?嗦,但是它有了比較完備的異常處理機(jī)制盲赊。
OutputStreamWriter out = ...
java.sql.Connection conn = ...
try {
Statement stat = conn.createStatement();
ResultSet rs = stat.executeQuery(
"select uid, name from user");
while (rs.next())
{
out.println("ID:" + rs.getString("uid") + "铣鹏,姓名: " + rs.getString("name"));
}
}
catch(SQLException sqlex)
{
out.println("警告:數(shù)據(jù)不完整");
throw new ApplicationException("讀取數(shù)據(jù)時(shí)出現(xiàn)SQL錯(cuò)誤", sqlex);
}
catch(IOException ioex)
{
throw new ApplicationException("寫入數(shù)據(jù)時(shí)出現(xiàn)IO錯(cuò)誤", ioex);
}
finally
{
if (conn != null) {
try {
conn.close();
}
catch(SQLException sqlex2)
{
System.err(this.getClass().getName() + ".mymethod - 不能關(guān)閉數(shù)據(jù)庫連接: " + sqlex2.toString());
}
}
if (out != null) {
try {
out.close();
}
catch(IOException ioex2)
{
System.err(this.getClass().getName() + ".mymethod - 不能關(guān)閉輸出文件" + ioex2.toString());
}
}
}
本文的結(jié)論不是放之四海皆準(zhǔn)的教條,有時(shí)常識(shí)和經(jīng)驗(yàn)才是最好的老師哀蘑。如果你對(duì)自己的做法沒有百分之百的信心诚卸,務(wù)必加上詳細(xì)、全面的注釋绘迁。
另一方面合溺,不要笑話這些錯(cuò)誤,不妨問問你自己是否真地徹底擺脫了這些壞習(xí)慣缀台。即使最有經(jīng)驗(yàn)的程序員偶爾也會(huì)誤入歧途棠赛,原因很簡(jiǎn)單,因?yàn)樗鼈兇_確實(shí)實(shí)帶來了“方便”膛腐。所有這些反例都可以看作Java編程世界的惡魔睛约,它們美麗動(dòng)人,無孔不入哲身,時(shí)刻誘惑著你辩涝。也許有人會(huì)認(rèn)為這些都屬于雞皮蒜毛的小事,不足掛齒勘天,但請(qǐng)記渍:勿以惡小而為之捉邢,勿以善小而不為。
------------------------------------------------------------------下面是一些java異常集-------------------------------------------------------------------------------------------
算術(shù)異常類:ArithmeticExecption
空指針異常類:NullPointerException
類型強(qiáng)制轉(zhuǎn)換異常:ClassCastException
數(shù)組負(fù)下標(biāo)異常:NegativeArrayException
數(shù)組下標(biāo)越界異常:ArrayIndexOutOfBoundsException
違背安全原則異常:SecturityException
文件已結(jié)束異常:EOFException
文件未找到異常:FileNotFoundException
字符串轉(zhuǎn)換為數(shù)字異常:NumberFormatException
操作數(shù)據(jù)庫異常:SQLException
輸入輸出異常:IOException
方法未找到異常:NoSuchMethodException
java.lang.AbstractMethodError
抽象方法錯(cuò)誤商膊。當(dāng)應(yīng)用試圖調(diào)用抽象方法時(shí)拋出伏伐。
java.lang.AssertionError
斷言錯(cuò)。用來指示一個(gè)斷言失敗的情況翘狱。
java.lang.ClassCircularityError
類循環(huán)依賴錯(cuò)誤秘案。在初始化一個(gè)類時(shí),若檢測(cè)到類之間循環(huán)依賴則拋出該異常潦匈。
java.lang.ClassFormatError
類格式錯(cuò)誤阱高。當(dāng)Java虛擬機(jī)試圖從一個(gè)文件中讀取Java類,而檢測(cè)到該文件的內(nèi)容不符合類的有效格式時(shí)拋出茬缩。
java.lang.Error
錯(cuò)誤赤惊。是所有錯(cuò)誤的基類,用于標(biāo)識(shí)嚴(yán)重的程序運(yùn)行問題凰锡。這些問題通常描述一些不應(yīng)被應(yīng)用程序捕獲的反常情況未舟。
java.lang.ExceptionInInitializerError
初始化程序錯(cuò)誤。當(dāng)執(zhí)行一個(gè)類的靜態(tài)初始化程序的過程中掂为,發(fā)生了異常時(shí)拋出裕膀。靜態(tài)初始化程序是指直接包含于類中的static語句段。
java.lang.IllegalAccessError
違法訪問錯(cuò)誤勇哗。當(dāng)一個(gè)應(yīng)用試圖訪問昼扛、修改某個(gè)類的域(Field)或者調(diào)用其方法,但是又違反域或方法的可見性聲明欲诺,則拋出該異常抄谐。
java.lang.IncompatibleClassChangeError
不兼容的類變化錯(cuò)誤。當(dāng)正在執(zhí)行的方法所依賴的類定義發(fā)生了不兼容的改變時(shí)扰法,拋出該異常蛹含。一般在修改了應(yīng)用中的某些類的聲明定義而沒有對(duì)整個(gè)應(yīng)用重新編譯而直接運(yùn)行的情況下,容易引發(fā)該錯(cuò)誤塞颁。
java.lang.InstantiationError
實(shí)例化錯(cuò)誤浦箱。當(dāng)一個(gè)應(yīng)用試圖通過Java的new操作符構(gòu)造一個(gè)抽象類或者接口時(shí)拋出該異常.
java.lang.InternalError
內(nèi)部錯(cuò)誤。用于指示Java虛擬機(jī)發(fā)生了內(nèi)部錯(cuò)誤祠锣。
java.lang.LinkageError
鏈接錯(cuò)誤酷窥。該錯(cuò)誤及其所有子類指示某個(gè)類依賴于另外一些類,在該類編譯之后锤岸,被依賴的類改變了其類定義而沒有重新編譯所有的類竖幔,進(jìn)而引發(fā)錯(cuò)誤的情況板乙。
java.lang.NoClassDefFoundError
未找到類定義錯(cuò)誤是偷。當(dāng)Java虛擬機(jī)或者類裝載器試圖實(shí)例化某個(gè)類拳氢,而找不到該類的定義時(shí)拋出該錯(cuò)誤。
java.lang.NoSuchFieldError
域不存在錯(cuò)誤蛋铆。當(dāng)應(yīng)用試圖訪問或者修改某類的某個(gè)域馋评,而該類的定義中沒有該域的定義時(shí)拋出該錯(cuò)誤。
java.lang.NoSuchMethodError
方法不存在錯(cuò)誤刺啦。當(dāng)應(yīng)用試圖調(diào)用某類的某個(gè)方法留特,而該類的定義中沒有該方法的定義時(shí)拋出該錯(cuò)誤。
java.lang.OutOfMemoryError
內(nèi)存不足錯(cuò)誤玛瘸。當(dāng)可用內(nèi)存不足以讓Java虛擬機(jī)分配給一個(gè)對(duì)象時(shí)拋出該錯(cuò)誤蜕青。
java.lang.StackOverflowError
堆棧溢出錯(cuò)誤。當(dāng)一個(gè)應(yīng)用遞歸調(diào)用的層次太深而導(dǎo)致堆棧溢出時(shí)拋出該錯(cuò)誤糊渊。
java.lang.ThreadDeath
線程結(jié)束右核。當(dāng)調(diào)用Thread類的stop方法時(shí)拋出該錯(cuò)誤,用于指示線程結(jié)束渺绒。
java.lang.UnknownError
未知錯(cuò)誤贺喝。用于指示Java虛擬機(jī)發(fā)生了未知嚴(yán)重錯(cuò)誤的情況。
java.lang.UnsatisfiedLinkError
未滿足的鏈接錯(cuò)誤宗兼。當(dāng)Java虛擬機(jī)未找到某個(gè)類的聲明為native方法的本機(jī)語言定義時(shí)拋出躏鱼。
java.lang.UnsupportedClassVersionError
不支持的類版本錯(cuò)誤。當(dāng)Java虛擬機(jī)試圖從讀取某個(gè)類文件殷绍,但是發(fā)現(xiàn)該文件的主染苛、次版本號(hào)不被當(dāng)前Java虛擬機(jī)支持的時(shí)候,拋出該錯(cuò)誤篡帕。
java.lang.VerifyError
驗(yàn)證錯(cuò)誤殖侵。當(dāng)驗(yàn)證器檢測(cè)到某個(gè)類文件中存在內(nèi)部不兼容或者安全問題時(shí)拋出該錯(cuò)誤。
java.lang.VirtualMachineError
虛擬機(jī)錯(cuò)誤镰烧。用于指示虛擬機(jī)被破壞或者繼續(xù)執(zhí)行操作所需的資源不足的情況拢军。
java.lang.ArithmeticException
算術(shù)條件異常。譬如:整數(shù)除零等怔鳖。
java.lang.ArrayIndexOutOfBoundsException
數(shù)組索引越界異常茉唉。當(dāng)對(duì)數(shù)組的索引值為負(fù)數(shù)或大于等于數(shù)組大小時(shí)拋出。
java.lang.ArrayStoreException
數(shù)組存儲(chǔ)異常结执。當(dāng)向數(shù)組中存放非數(shù)組聲明類型對(duì)象時(shí)拋出度陆。
java.lang.ClassCastException
類造型異常。假設(shè)有類A和B(A不是B的父類或子類)献幔,O是A的實(shí)例懂傀,那么當(dāng)強(qiáng)制將O構(gòu)造為類B的實(shí)例時(shí)拋出該異常。該異常經(jīng)常被稱為強(qiáng)制類型轉(zhuǎn)換異常蜡感。
java.lang.ClassNotFoundException
找不到類異常蹬蚁。當(dāng)應(yīng)用試圖根據(jù)字符串形式的類名構(gòu)造類恃泪,而在遍歷CLASSPAH之后找不到對(duì)應(yīng)名稱的class文件時(shí),拋出該異常犀斋。
java.lang.CloneNotSupportedException
不支持克隆異常贝乎。當(dāng)沒有實(shí)現(xiàn)Cloneable接口或者不支持克隆方法時(shí),調(diào)用其clone()方法則拋出該異常。
java.lang.EnumConstantNotPresentException
枚舉常量不存在異常叽粹。當(dāng)應(yīng)用試圖通過名稱和枚舉類型訪問一個(gè)枚舉對(duì)象览效,但該枚舉對(duì)象并不包含常量時(shí),拋出該異常虫几。
java.lang.Exception
根異常锤灿。用以描述應(yīng)用程序希望捕獲的情況。
java.lang.IllegalAccessException
違法的訪問異常辆脸。當(dāng)應(yīng)用試圖通過反射方式創(chuàng)建某個(gè)類的實(shí)例衡招、訪問該類屬性、調(diào)用該類方法每强,而當(dāng)時(shí)又無法訪問類的始腾、屬性的、方法的或構(gòu)造方法的定義時(shí)拋出該異常空执。
java.lang.IllegalMonitorStateException
違法的監(jiān)控狀態(tài)異常浪箭。當(dāng)某個(gè)線程試圖等待一個(gè)自己并不擁有的對(duì)象(O)的監(jiān)控器或者通知其他線程等待該對(duì)象(O)的監(jiān)控器時(shí),拋出該異常辨绊。
java.lang.IllegalStateException
違法的狀態(tài)異常奶栖。當(dāng)在Java環(huán)境和應(yīng)用尚未處于某個(gè)方法的合法調(diào)用狀態(tài),而調(diào)用了該方法時(shí)门坷,拋出該異常宣鄙。
java.lang.IllegalThreadStateException
違法的線程狀態(tài)異常。當(dāng)縣城尚未處于某個(gè)方法的合法調(diào)用狀態(tài)默蚌,而調(diào)用了該方法時(shí)冻晤,拋出異常。
java.lang.IndexOutOfBoundsException
索引越界異常绸吸。當(dāng)訪問某個(gè)序列的索引值小于0或大于等于序列大小時(shí)鼻弧,拋出該異常。
java.lang.InstantiationException
實(shí)例化異常锦茁。當(dāng)試圖通過newInstance()方法創(chuàng)建某個(gè)類的實(shí)例攘轩,而該類是一個(gè)抽象類或接口時(shí),拋出該異常码俩。
java.lang.InterruptedException
被中止異常度帮。當(dāng)某個(gè)線程處于長(zhǎng)時(shí)間的等待、休眠或其他暫停狀態(tài)稿存,而此時(shí)其他的線程通過Thread的interrupt方法終止該線程時(shí)拋出該異常笨篷。
java.lang.NegativeArraySizeException
數(shù)組大小為負(fù)值異常甫菠。當(dāng)使用負(fù)數(shù)大小值創(chuàng)建數(shù)組時(shí)拋出該異常。
java.lang.NoSuchFieldException
屬性不存在異常冕屯。當(dāng)訪問某個(gè)類的不存在的屬性時(shí)拋出該異常。
java.lang.NoSuchMethodException
方法不存在異常拂苹。當(dāng)訪問某個(gè)類的不存在的方法時(shí)拋出該異常安聘。
java.lang.NullPointerException
空指針異常。當(dāng)應(yīng)用試圖在要求使用對(duì)象的地方使用了null時(shí)瓢棒,拋出該異常浴韭。譬如:調(diào)用null對(duì)象的實(shí)例方法、訪問null對(duì)象的屬性脯宿、計(jì)算null對(duì)象的長(zhǎng)度念颈、使用throw語句拋出null等等。
java.lang.NumberFormatException
數(shù)字格式異常连霉。當(dāng)試圖將一個(gè)String轉(zhuǎn)換為指定的數(shù)字類型榴芳,而該字符串確不滿足數(shù)字類型要求的格式時(shí),拋出該異常跺撼。
java.lang.RuntimeException
運(yùn)行時(shí)異常窟感。是所有Java虛擬機(jī)正常操作期間可以被拋出的異常的父類。
java.lang.SecurityException
安全異常歉井。由安全管理器拋出柿祈,用于指示違反安全情況的異常。
java.lang.StringIndexOutOfBoundsException
字符串索引越界異常哩至。當(dāng)使用索引值訪問某個(gè)字符串中的字符躏嚎,而該索引值小于0或大于等于序列大小時(shí),拋出該異常菩貌。
java.lang.TypeNotPresentException
類型不存在異常卢佣。當(dāng)應(yīng)用試圖以某個(gè)類型名稱的字符串表達(dá)方式訪問該類型,但是根據(jù)給定的名稱又找不到該類型是拋出該異常箭阶。該異常與ClassNotFoundException的區(qū)別在于該異常是unchecked(不被檢查)異常珠漂,而ClassNotFoundException是checked(被檢查)異常。
java.lang.UnsupportedOperationException
不支持的方法異常尾膊。指明請(qǐng)求的方法不被支持情況的異常媳危。
異常
javax.servlet.jsp.JspException: Cannot retrieve mapping for action /Login (/Login是你的action名字)
可能原因
action沒有再struts-config.xml 中定義,或沒有找到匹配的action冈敛,例如在JSP文件中使用
-----------------------------------------------------------------------------------------------------------------
異常
org.apache.jasper.JasperException: Cannot retrieve definition for form bean null
可能原因
這個(gè)異常是因?yàn)镾truts根據(jù)struts-config.xml中的mapping沒有找到action期望的form bean待笑。大部分的情況可能是因?yàn)樵趂orm-bean中設(shè)置的name屬性和action中設(shè)置的name屬性不匹配所致。換句話說,action和form都應(yīng)該各自有一個(gè)name屬性句各,并且要精確匹配,包括大小寫蛹批。這個(gè)錯(cuò)誤當(dāng)沒有name屬性和action關(guān)聯(lián)時(shí)也會(huì)發(fā)生仰泻,如果沒有在action中指定name屬性荆陆,那么就沒有name屬性和action相關(guān)聯(lián)。當(dāng)然當(dāng)action制作某些控制時(shí)集侯,譬如根據(jù)參數(shù)值跳轉(zhuǎn)到相應(yīng)的jsp頁面被啼,而不是處理表單數(shù)據(jù),這是就不用name屬性棠枉,這也是action的使用方法之一浓体。
-----------------------------------------------------------------------------------------------------------------
異常
No action instance for path /xxxx could be created
可能原因
特別提示:因?yàn)橛泻芏嘀星闆r會(huì)導(dǎo)致這個(gè)錯(cuò)誤的發(fā)生,所以推薦大家調(diào)高你的web服務(wù)器的日志/調(diào)試級(jí)別辈讶,這樣可以從更多的信息中看到潛在的命浴、在試圖創(chuàng)建action類時(shí)發(fā)生的錯(cuò)誤,這個(gè)action類你已經(jīng)在struts-config.xml中設(shè)置了關(guān)聯(lián)(即添加了標(biāo)簽)贱除。
在struts-config.xml中通過action標(biāo)簽的class屬性指定的action類不能被找到有很多種原因生闲,例如:定位編譯后的.class文件失敗。Failure to place compiled .class file for the action in the classpath (在web開發(fā)中月幌,class的的位置在r WEB-INF/classes跪腹,所以你的action class必須要在這個(gè)目錄下。例如你的action類位于WEB-INF/classes/action/Login.class,那么在struts-config.xml中設(shè)置action的屬性type時(shí)就是action.Login).
拼寫錯(cuò)誤飞醉,這個(gè)也時(shí)有發(fā)生冲茸,并且不易找到,特別注意第一個(gè)字母的大小寫和包的名稱缅帘。
-----------------------------------------------------------------------------------------------------------------
異常
javax.servlet.jsp.JspException: No getter method for property username of bean org.apache.struts.taglib.html.BEAN
可能原因
沒有位form bean中的某個(gè)變量定義getter 方法
這個(gè)錯(cuò)誤主要發(fā)生在表單提交的FormBean中轴术,用struts標(biāo)記時(shí),在FormBean中必須有一個(gè)getUsername()方法钦无。注意字母“U”逗栽。
-----------------------------------------------------------------------------------------------------------------
異常
java.lang.NoClassDefFoundError: org/apache/struts/action/ActionForm
可能原因
這個(gè)錯(cuò)誤主要發(fā)生在在classpath中找不到相應(yīng)的Java .class文件。如果這個(gè)錯(cuò)誤發(fā)生在web應(yīng)用程序的運(yùn)行時(shí)失暂,主要是因?yàn)橹付ǖ腸lass文件不在web server的classpath中(/WEB-INF/classes 和 /WEB-INF/lib)彼宠。在上面的錯(cuò)誤中,原因是找不到ActionForm類弟塞。
-----------------------------------------------------------------------------------------------------------------
異常
javax.servlet.jsp.JspException: Exception creating bean of class org.apache.struts.action.ActionForm: {1}
可能原因
Instantiating Struts-provided ActionForm class directly instead of instantiating a class derived off ActionForm. This mightoccur implicitly if you specify that a form-bean is this Struts ActionForm class rather than specifying a child of this classfor the form-bean.
Not associating an ActionForm-descended class with an action can also lead to this error.
-----------------------------------------------------------------------------------------------------------------
異常
javax.servlet.jsp.JspException: Cannot find ActionMappings or ActionFormBeans collection
可能原因
不是標(biāo)識(shí)Struts actionServlet的標(biāo)記就是映射.do擴(kuò)展名的標(biāo)記或者兩者都沒有在web.xml中聲明凭峡。
在struts-config.xml中的打字或者拼寫錯(cuò)誤也可導(dǎo)致這個(gè)異常的發(fā)生。例如缺少一個(gè)標(biāo)記的關(guān)閉符號(hào)/>决记。最好使用struts console工具檢查一下摧冀。
另外,load-on-startup必須在web.xml中聲明,這要么是一個(gè)空標(biāo)記索昂,要么指定一個(gè)數(shù)值建车,這個(gè)數(shù)值用來表servlet運(yùn)行的優(yōu)先級(jí),數(shù)值越大優(yōu)先級(jí)越低椒惨。
還有一個(gè)和使用load-on-startup有關(guān)的是使用Struts預(yù)編譯JSP文件時(shí)也可能導(dǎo)致這個(gè)異常缤至。
-----------------------------------------------------------------------------------------------------------------
異常
java.lang.NullPointerException at org.apache.struts.util.RequestUtils.forwardURL(RequestUtils.java:1223)
可能原因
在struts-config.xml中的forward元素缺少path屬性。例如應(yīng)該是如下形式:
-----------------------------------------------------------------------------------------------------------------
異常
javax.servlet.jsp.JspException: Cannot find bean org.apache.struts.taglib.html.BEAN in any scope
Probable Causes
試圖在Struts的form標(biāo)記外使用form的子元素康谆。這常常發(fā)生在你在后面使用Struts的html標(biāo)記领斥。另外要注意可能你不經(jīng)意使用的無主體的標(biāo)記,如秉宿,這樣web 服務(wù)器解析時(shí)就當(dāng)作一個(gè)無主體的標(biāo)記,隨后使用的所有標(biāo)記都被認(rèn)為是在這個(gè)標(biāo)記之外的屯碴,如又使用了還有就是在使用taglib引入HTML標(biāo)記庫時(shí)描睦,你使用的prefix的值不是html。
-----------------------------------------------------------------------------------------------------------------
異常
javax.servlet.jsp.JspException: Missing message for key xx.xx.xx
Probable Causes
這個(gè)key的值對(duì)沒有在資源文件ApplicationResources.properties中定義导而。如果你使用eclipse時(shí)經(jīng)常碰到這樣的情況忱叭,當(dāng)項(xiàng)目重新編譯時(shí),eclipse會(huì)自動(dòng)將classes目錄下的資源文件刪除今艺。
資源文件ApplicationResources.properties 不在classpath中應(yīng)將資源文件放到 WEB-INF/classes 目錄下韵丑,當(dāng)然要在struts-config.xml中定義)
-----------------------------------------------------------------------------------------------------------------
異常
Cannot find message resources under key org.apache.struts.action.MESSAGE
可能原因
很顯然,這個(gè)錯(cuò)誤是發(fā)生在使用資源文件時(shí)虚缎,而Struts沒有找到資源文件撵彻。
Implicitly trying to use message resources that are not available (such as using empty html:options tag instead of specifyingthe options in its body -- this assumes options are specified in ApplicationResources.properties file)
XML parser issues -- too many, too few, incorrect/incompatible versions
-----------------------------------------------------------------------------------------------------------------
異常
Strange and seemingly random characters in HTML and on screen, but not in original JSP or servlet.
可能原因
混和使用Struts的html:form標(biāo)記和標(biāo)準(zhǔn)的HTML標(biāo)記不正確。
使用的編碼樣式在本頁中不支持实牡。
-----------------------------------------------------------------------------------------------------------------
異常
"Document contained no data" in Netscape
No data rendered (completely empty) page in Microsoft Internet Explorer
可能原因
使用一個(gè)Action的派生類而沒有實(shí)現(xiàn)perform()方法或execute()方法陌僵。在Struts1.0中實(shí)現(xiàn)的是perform()方法,在Struts1.1中實(shí)現(xiàn)的是execute()方法创坞,但Struts1.1向后兼容perform()方法碗短。但你使用Struts1.1創(chuàng)建一個(gè)Action的派生類,并且實(shí)現(xiàn)了execute()方法题涨,而你在Struts1.0中運(yùn)行的話偎谁,就會(huì)得到"Document contained nodata" error message in Netscape or a completely empty (no HTML whatsoever) page rendered in Microsoft Internet Explorer.”的錯(cuò)誤信息。
---------------------------------------------------------------------------------------------------------------------------
異常
ServletException: BeanUtils.populate
解決方案
在用Struts上傳文件時(shí),遇到了javax.servlet.ServletException: BeanUtils.populate異常纲堵。
我的ActionServlet并沒有用到BeanUtils這些工具類巡雨。后來仔細(xì)檢查代碼發(fā)現(xiàn)是在jsp文件里的form忘了加enctype="multipart/form-data" 了。所以寫程序遇到錯(cuò)誤或異常應(yīng)該從多方面考慮問題存在的可能性席函,想到系統(tǒng)提示信息以外的東西鸯隅。
----------------------------------------------------------------------------------------------------------------------------
1. 定義Action后, 如果指定了name, 那么必須要定義一個(gè)與它同名的FormBean才能進(jìn)行form映射.2. 如果定義Action后, 提交頁面時(shí)出現(xiàn) "No input attribute for mapping path..." 錯(cuò)誤, 則需要在其input屬性中定義轉(zhuǎn)向的頁面.3. 如果插入新的數(shù)據(jù)時(shí)出現(xiàn) "Batch update row count wrong:..." 錯(cuò)誤, 則說明XXX.hbm.xml中指定的key的類型為原始類型(int, long),因?yàn)檫@種類型會(huì)自動(dòng)分配值, 而這個(gè)值往往會(huì)讓系統(tǒng)認(rèn)為已經(jīng)存在該記錄, 正確的方法是使用java.lang.Integer或java.lang.Long對(duì)象.4. 如果插入數(shù)據(jù)時(shí)出現(xiàn) "argument type mismatch" 錯(cuò)誤, 可能是你使用了Date等特殊對(duì)象, 因?yàn)閟truts不能自動(dòng)從String型轉(zhuǎn)換成Date型,所以, 你需要在Action中手動(dòng)把String型轉(zhuǎn)換成Date型.5. Hibernate中, Query的iterator()比list()方法快很多.6. 如果出現(xiàn) "equal symbol expected" 錯(cuò)誤, 說明你的strtus標(biāo)簽中包含另一個(gè)標(biāo)簽或者變量, 例如:
">
或者
"/>
這樣的情況...
---------------------------------------------------------------------------------------------------------------------------
錯(cuò)誤:Exception in thread "main" org.hibernate.exception.SQLGrammarException: Could not execute JDBC batch update原因與解決:????? 因?yàn)镠ibernate Tools(或者Eclipse本身的Database Explorer)生成*.hbn.xml工具中包含有catalog="***"(*表示數(shù)據(jù)庫名稱)這樣的屬性,將該屬性刪除就可以了
---------------------------------------------------------------------------------------------------------------------------
錯(cuò)誤:org.hibernate.ObjectDeletedException: deleted object would be re-saved by cascade (remove deleted object from associations)
原因與解決:
方法1 刪除Set方的cascade
方法2 解決關(guān)聯(lián)關(guān)系后,再刪除
方法3 在many-to-one方增加cascade 但值不能是none
最后一招:
檢查一下hashCode equals是否使用了id作為唯一標(biāo)示的選項(xiàng)了;我用uuid.hex時(shí)是沒有問題的蝌以;但是用了native炕舵,就不行了,怎么辦跟畅?刪除把式睢!
----------------------------------------------------------------------------------------------------------------------------
問題:今天用Tomcat 5.5.12徊件,發(fā)現(xiàn)原來很好用的系統(tǒng)不能用了奸攻,反復(fù)測(cè)試發(fā)現(xiàn)頁面中不能包含 taglib,否則會(huì)出現(xiàn)以下提示:HTTP Status 500 -type Exception reportMessage description The server encountered an internal error () that prevented it from fulfilling this request.exceptionorg.apache.jasper.JasperException: /index.jsp(1,1) Unable to read TLD "META-INF/tlds/struts-bean.tld" from JAR file"file:*****/WEB-INF/lib/struts.jar":原因:更新了工程用的lib文件夾下的jar虱痕,發(fā)布時(shí)也發(fā)布了servlet.jar和jsp-api.jar睹耐。解決:把jsp-api.jar刪除就解決這個(gè)問題了。-----------------------------------------------------------------------------------------------------------------------------
錯(cuò)誤: java.lang.NullPointerException
原因: 發(fā)現(xiàn) dao 實(shí)例部翘、 manage 實(shí)例等需要注入的東西沒有被注入(俗稱空指針異常)解決:這個(gè)時(shí)候硝训,你應(yīng)該查看日志文件;默認(rèn)是應(yīng)用服務(wù)器的 log 文件新思,比如 Tomcat 就是 [Tomcat 安裝目錄 ]/logs 窖梁;你會(huì)發(fā)現(xiàn)提示你:可能是:org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sf' defined in ServletContextresource [/WEB-INF/applicationContext.xml]: Initialization of bean failed; nested exception isorg.hibernate.HibernateException: could not configure from URL: file:src/hibernate.cfg.xmlorg.hibernate.HibernateException: could not configure from URL: file:src/hibernate.cfg.xml……………………….Caused by: java.io.FileNotFoundException: src\hibernate.cfg.xml可能是:org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined inServletContext resource [/WEB-INF/applicationContext.xml]: Initialization of bean failed; nested exception isorg.hibernate.MappingException: Resource: com/mcc/coupon/model/UserRole.hbm.xml not foundorg.hibernate.MappingException: Resource: com/mcc/coupon/model/UserRole.hbm.xml not found然后你就知道原因是因?yàn)榕渲梦募慕馕龀隽隋e(cuò)誤,這個(gè)通過 Web 頁面是看不出來的夹囚。更多的是持久化影射文件出的錯(cuò)誤纵刘;導(dǎo)致了沒有被解析;當(dāng)然你需要的功能就無法使用了荸哟。
----------------------------------------------------------------------------------------------------------------------------
錯(cuò)誤:StandardWrapperValve[action]: Servlet.service() for servlet action threw exception
javax.servlet.jsp.JspException: Cannot retrieve mapping for action /settlementTypeManage
或者:????? type Status report????? message Servlet action is not available????? description The requested resource (Servlet action is not available) is not available.
原因: 同 上
----------------------------------------------------------------------------------------------------------------------------
錯(cuò)誤StandardWrapperValve[jsp]: Servlet.service() for servlet jsp threw exceptionjava.lang.ClassNotFoundException: org.apache.struts.taglib.bean.CookieTei界面錯(cuò)誤具體描述:
org.apache.jasper.JasperException: Failed to load or instantiate TagExtraInfo class: org.apache.struts.taglib.bean.CookieTei
原因與解決:??? <方案一>你的“html:”開頭的標(biāo)簽沒有放在一個(gè)中?????? <方案二>重新啟動(dòng)你的應(yīng)用服務(wù)器假哎,自動(dòng)就沒有這個(gè)問題