異常
26.?finally與中斷
- //該方法返回false ??
- static ? boolean ?f()?{??
- ? try ?{??
- ?? return ? true ;??
- ?}? finally ?{??
- ?? return ? false ;??
- ?}??
- }??
不要用return、break、continue或throw來(lái)退出finally語(yǔ)句塊,并且千萬(wàn)不要允許受檢查的異常傳播到finally語(yǔ)句
塊之外。也就是說(shuō)不要在finally塊內(nèi)終止程序,而是執(zhí)行完finally塊后,要將控制權(quán)移交給try塊,由try最終決定
怎樣結(jié)束方法的調(diào)用。
?
對(duì)于任何在finally語(yǔ)句塊中可能拋出的受檢查異常都要進(jìn)行處理,而不是任其傳播,下面流拷貝程序在關(guān)閉流時(shí)沒(méi)有
防止異常的傳播,這會(huì)有問(wèn)題:
- static ? void ?copy(String?src,?String?dest)? throws ?IOException?{??
- ?InputStream?in?=? null ;??
- ?OutputStream?out?=? null ;??
- ? try ?{??
- ??in?=? new ?FileInputStream(src);??
- ??out?=? new ?FileOutputStream(dest);??
- ?? byte []?buf?=? new ? byte [ 1024 ];??
- ?? int ?n;??
- ?? while ?((n?=?in.read(buf))?>=? 0 )?{??
- ???out.write(buf,? 0 ,?n);??
- ??}??
- ?}? finally {??
- ?? //這里應(yīng)該使用try-catch將每個(gè)close包裝起來(lái) ??
- ?? if (in?!=? null ){in.close();}??
- ?? if (in?!=? null ){out.close();}??
- ?}??
- }??
catch塊中的return語(yǔ)句是不會(huì)阻止finally塊執(zhí)行的,那么catch塊中的continue和break能否阻止?答案是不會(huì)的,
與return一樣,finally語(yǔ)句塊是在循環(huán)被跳過(guò)(continue)和中斷(break)之前被執(zhí)行的:
- int ?i?=? 0 ;??
- System.out.println( "--continue--" );??
- while ?(i++?<=? 1 )?{??
- ? try ?{??
- ??System.out.println( "i=" ?+?i);??
- ?? continue ;??
- ?}? catch ?(Exception?e)?{??
- ?}? finally ?{??
- ??System.out.println( "finally" );??
- ?}??
- }??
- System.out.println( "--break--" );??
- while ?(i++?<=? 3 )?{??
- ? try ?{??
- ??System.out.println( "i=" ?+?i);??
- ?? break ;??
- ?}? catch ?(Exception?e)?{??
- ?}? finally ?{??
- ??System.out.println( "finally" );??
- ?}??
- }??
27.?catch捕獲異常規(guī)則
捕獲RuntimeException、Exception或Throwable的catch語(yǔ)句是合法,不管try塊里是否拋出了這三個(gè)異常。但如果try
塊沒(méi)有拋出或不可能拋出檢測(cè)性異常,則catch不能捕獲這些異常,如IOException異常:
- public ? class ?Test?{??
- ? public ? static ? void ?main(String[]?args)?{??
- ?? try {??
- ??? //... ??
- ??} catch ?(Exception?e)?{??
- ?????
- ??} catch ?(Throwable?e)?{??
- ?????
- ??}??
- ????
- ?? /*?!!?編譯出錯(cuò) ?
- ???try{ ?
- ????//... ?
- ???}catch?(IOException?e)?{ ?
- ???? ?
- ???} ?
- ???*/ ??
- ?}??
- }??
28.?重寫(xiě)時(shí)方法異常范圍
重寫(xiě)或?qū)崿F(xiàn)時(shí)不能擴(kuò)大異常的范圍,如果是多繼承,則異常取所有父類(lèi)方法異常的交集或不拋出異常:
- interface ?I1?{??
- ? void ?f()? throws ?Exception;??
- }??
- ??
- interface ?I2?{??
- ? void ?f()? throws ?IOException;??
- }??
- ??
- interface ?I3? extends ?I1,?I2?{}??
- ??
- class ?Imp? implements ?I3?{??
- ? //?不能編譯通過(guò),多繼承時(shí)只能取父類(lèi)方法異常交集,這樣就不會(huì)擴(kuò)大異常范圍 ??
- ? //?!!?void?f?()?throws?Exception; ??
- ? //?void?f();//?能編譯通過(guò) ??
- ? //?能編譯通過(guò),Exception與IOException的交集為IOException ??
- ? public ? void ?f()? throws ?IOException?{??
- ?}??
- }??
29.?靜態(tài)與非靜態(tài)final常量不能在catch塊中初始化
?
靜態(tài)與非靜態(tài)塊中如果拋出了異常,則一定要使用try-catch塊來(lái)捕獲。
- public ? class ?Test?{??
- ? static ? final ? int ?i;??
- ? static ?{??
- ?? try ?{??
- ???i?=?f();??
- ??}? catch ?(RuntimeException?e)?{??
- ???i?=? 1 ;??
- ??}??
- ?}??
- ??
- ? static ? int ?f()?{??
- ?? throw ? new ?RuntimeException();??
- ?}??
- }??
上面的程序編譯不能通過(guò)。表面上是可以的,因?yàn)閕第一次初始化時(shí)可能拋出異常,所以?huà)伄惓r(shí)可以在catch塊中初
始化,最終還是只初始化一次,這正是空f(shuō)inal所要求的,但為什么編譯器不知道這些呢?
?
要確定一個(gè)程序是否不止一次地對(duì)一個(gè)空f(shuō)inal進(jìn)行賦值是很困難的問(wèn)題。語(yǔ)言規(guī)范在這一點(diǎn)上采用了保守的方式。
30.?System.exit()與finally
- try ?{??
- ?System.out.println( "Hello?world" );??
- ?System.exit( 0 );??
- ? //?或者使用Runtime退出系統(tǒng) ??
- ? //?Runtime.getRuntime().exit(0); ??
- }? finally ?{??
- ?System.out.println( "Goodbyte?world" );??
- }??
上面的程序會(huì)打印出"Goodbyte world"嗎?不會(huì)。
?
System.exit將立即停止所有的程序線(xiàn)程,它并不會(huì)使finally語(yǔ)句塊得到調(diào)用,但是它在停止VM之前會(huì)執(zhí)行關(guān)閉掛鉤
操作(這此掛鉤操作是注冊(cè)到Runtime.addShutdownHook上的線(xiàn)程),這對(duì)于釋放VM之外的資源很有幫助。使用掛鉤程
序修改上面程序:
- System.out.println( "Hello?world" );??
- Runtime.getRuntime().addShutdownHook( new ?Thread()?{??
- ? public ? void ?run()?{??
- ??System.out.println( "Goodbyte?world" );??
- ?}??
- });??
- System.exit( 0 );??
?
另外,對(duì)象回收時(shí),使用VM調(diào)用對(duì)象的finalize()方法有兩種:
System.runFinalization():該方法讓虛擬機(jī)也只是盡最大努力去完成所有未執(zhí)行的finalize()終止方法,但不一定
會(huì)執(zhí)行。
System.runFinalizersOnExit(true):該方法一定會(huì)回收,但不安全,已被廢棄。因?yàn)樗赡軐?duì)正在使用的對(duì)象調(diào)用
終結(jié)方法,而其他線(xiàn)程同時(shí)正在操作這些對(duì)象,從而導(dǎo)致不正確的行為或死鎖。
?
為了加快垃圾回收,使用System.gc(),但不一定馬上執(zhí)行加收動(dòng)作,由虛擬機(jī)決定,實(shí)質(zhì)上是調(diào)用
Runtime.getRuntime().gc()。
?
System的很多方法都是調(diào)用Runtime類(lèi)的相關(guān)方法來(lái)實(shí)現(xiàn)的。
31.?遞歸構(gòu)造
- public ? class ?S??{??
- ? private ?S?instance?=? new ?S();??
- ? public ?S()?{}??
- }??
如果在程序外面構(gòu)造該類(lèi)的實(shí)例,則會(huì)拋出java.lang.StackOverflowError錯(cuò)誤。其原因是實(shí)例變量的初始化操作將
先于構(gòu)造器的程序體而運(yùn)行。
32.?構(gòu)造器中的異常
如果父類(lèi)構(gòu)造器拋出了檢測(cè)異常,則子類(lèi)也只能拋出,而不能采用try-catch來(lái)捕獲:
- public ? class ?P?{??
- ? public ?P()? throws ?Exception?{}??
- }??
- ??
- class ?S? extends ?P?{??
- ? public ?S()? throws ?Exception?{??
- ?? try ?{??
- ??? //?不能在try塊中明確調(diào)用父類(lèi)構(gòu)造器,因?yàn)闃?gòu)造的 ??
- ??? //?明確調(diào)用只能放在第一行 ??
- ??? //?!!?super(); ??
- ?? //try-catch不能捕獲到父類(lèi)構(gòu)造器所拋出的異常,子類(lèi)只能拋出 ??
- ??}? catch ?(Exception?e)?{??
- ??}??
- ?}??
- }??
?
如果初使化實(shí)例屬性時(shí)拋出了異常,則構(gòu)造器只能拋出異常,在構(gòu)造器中捕獲不起作用:
- public ? class ?A?{??
- ???? private ?String?str?=?String. class .newInstance();??
- ??
- ???? public ?A()? throws ?InstantiationException,?IllegalAccessException?{}??
- ??
- ???? public ?A( int ?i)? throws ?Exception?{??
- ???????? try ?{ //即使這里捕獲了,方法簽名還是得要拋出 ??
- ??
- ????????}? catch ?(Exception?e)?{??
- ??
- ????????}??
- ????}??
- ??
- ???? /* ?
- ?????*?!!編譯不能通過(guò),因?yàn)閟tr2為靜態(tài)的,他不能通過(guò)構(gòu)造器來(lái)捕獲,所以只 ?
- ?????*?能使用靜態(tài)方法來(lái)捕獲。即初始化靜態(tài)成員時(shí)不能拋出捕獲性異常。? ?
- ?????*/ ??
- ???? //!!private?static?String?str2?=?String.class.newInstance(); ??
- ??????
- ???? //?只能使用靜態(tài)方法來(lái)捕獲異常,如果是拋出的運(yùn)行時(shí)異常則不需要捕獲 ??
- ???? private ? static ?String?str2?=?newInstance();??
- ??
- ???? private ? static ?String?newInstance()? throws ?RuntimeException?{??
- ???????? try ?{??
- ???????????? return ?String. class .newInstance();??
- ????????}? catch ?(Exception?e)?{??
- ????????????e.printStackTrace();??
- ????????}??
- ???????? return ? null ;??
- ????}??
- }??
33.?StackOverflowError
Java虛擬機(jī)對(duì)棧的深度限制到了某個(gè)值,當(dāng)超過(guò)這個(gè)值時(shí),VM就拋出StackOverflowError。一般VM都將棧的深度限制
為1024,即當(dāng)方法調(diào)用方法的層次超過(guò)1024時(shí)就會(huì)產(chǎn)生StackOverflowError。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
