,史上最全的教程來啦~)
創(chuàng)作不易如果覺得這篇文章對你有幫助歡迎各位老鐵點(diǎn)個(gè)贊唄您的支持是我創(chuàng)作的最大動(dòng)力文章目錄1 前言2 什么是異常3 異常的分類3.1 異常的類圖結(jié)構(gòu)3.2 異常的分類4 異常的處理4.1 異常捕獲處理4.1.1 try、catch和finally4.1.2 異常捕獲處理4.1.3 異常的捕獲順序4.2 throws拋出處理4.3 getMessage()和printStackTrace()4.4 方法覆蓋中的異常處理5 異常相關(guān)的面試題5.1 談?wù)勀鉐ava異常處理機(jī)制的理解5.2 throw 和 throws 的區(qū)別5.3 final、finally、finalize 的區(qū)別5.4 Java中異常分為哪些種類5.5 error和exception的區(qū)別5.6 說出最常見的5個(gè)RuntimeException5.7 調(diào)用下面的方法得到的返回值是什么5.8 java 中如何編寫自定義異常6 總結(jié)1 前言Java中的Exception也是很重要的一部分雖然經(jīng)常使用Exception但是基礎(chǔ)知識(shí)比較零散這里筆者也做一下總結(jié)吧有利于以后形成良好的知識(shí)體系。2 什么是異常定義在程序運(yùn)行過程中出現(xiàn)的錯(cuò)誤稱為異常。異常就是程序運(yùn)行過程中出現(xiàn)了不正?,F(xiàn)象導(dǎo)致程序的中斷。在Java中把各種異?,F(xiàn)象進(jìn)行了抽象形成了異常類。3 異常的分類3.1 異常的類圖結(jié)構(gòu)先來整體認(rèn)識(shí)下異常的類圖結(jié)構(gòu)3.2 異常的分類異常主要分為錯(cuò)誤、一般性異常受控異常、運(yùn)行時(shí)異常非受控異常錯(cuò)誤如果應(yīng)用程序出現(xiàn)了Error那么將無法恢復(fù)只能重新啟動(dòng)應(yīng)用程序最典型的Error的異常是OutOfMemoryError受控異常這種異常屬于一般性異常出現(xiàn)了這種異常必須顯示的處理不顯示處理java程序?qū)o法編譯通過。編譯器強(qiáng)制普通異常必須try…catch處理或用throws聲明繼續(xù)拋給上層調(diào)用方法處理所以普通異常也稱為checked異常。非受控異常非受控異常也即是運(yùn)行時(shí)異常RuntimeException這種系統(tǒng)異??梢蕴幚硪部梢圆惶幚硭跃幾g器不強(qiáng)制用try…catch處理或用throws聲明所以系統(tǒng)異常也稱為unchecked異常。此種異??梢圆挥蔑@示的處理例如被0除異常java沒有要求我們一定要處理 當(dāng)出現(xiàn)這種異常時(shí)肯定是程序員的問題也就是說健壯的程序一般不會(huì)出現(xiàn)這種系統(tǒng)異常。4 異常的處理運(yùn)行時(shí)異常系統(tǒng)異常不需要預(yù)處理通過規(guī)范的代碼可以避免產(chǎn)生這種異常受檢異常編譯時(shí)異常必須預(yù)處理否則編譯報(bào)錯(cuò)有兩種預(yù)處理方式 :捕獲處理拋出處理4.1 異常捕獲處理4.1.1 try、catch和finally異常的捕獲和處理需要采用try和catch來處理具體格式如下try{}catch(OneExceptione){}catch(TwoExceptione){}finally{}try中包含了可能產(chǎn)生異常的代碼try后面是catchcatch可以有一個(gè)或多個(gè)catch中是需要捕獲的異常當(dāng)try中的代碼出現(xiàn)異常時(shí)出現(xiàn)異常下面的代碼不會(huì)執(zhí)行馬上會(huì)跳轉(zhuǎn)到相應(yīng)的catch語句塊中如果沒有異常不會(huì)跳轉(zhuǎn)到catch中finally表示不管是出現(xiàn)異常還是沒有出現(xiàn)異常finally里的代碼都執(zhí)行finally和catch可以分開使用但finally必須和try一塊使用如下格式使用finally也是正確的try{}finally{}4.1.2 異常捕獲處理異常捕獲處理詳細(xì)說明privatestaticvoidtestException2(){try{//1、對可能產(chǎn)生異常的代碼進(jìn)行檢視//2、如果try代碼塊的某條語句產(chǎn)生了異常, 就立即跳轉(zhuǎn)到catch子句執(zhí)行, try代碼塊后面的代碼不再執(zhí)行//3、try代碼塊可能會(huì)有多個(gè)受檢異常需要預(yù)處理, 可以通過多個(gè)catch子句分別捕獲}catch(異常類型1e1){//捕獲異常類型1的異常, 進(jìn)行處理//在開發(fā)階段, 一般的處理方式要么獲得異常信息, 要么打印異常棧跟蹤信息(e1.printStackTrace())//在部署后, 如果有異常, 一般把異常信息打印到日志文件中, 如logger.error(e1.getMessage());}catch(異常類型2e1){//捕獲異常類型2的異常, 進(jìn)行處理//如果捕獲的異常類型有繼承關(guān)系, 應(yīng)該先捕獲子異常再捕獲父異常//如果沒有繼承關(guān)系, catch子句沒有先后順序}finally{//不管是否產(chǎn)生了異常, finally子句總是會(huì)執(zhí)行//一般情況下, 會(huì)在finally子句中釋放系統(tǒng)資源}}【代碼示例】privatestaticvoidtestException3(){inti1100;inti20;//try里是可能出現(xiàn)異常的代碼try{//當(dāng)出現(xiàn)被0除異常時(shí)程序流程會(huì)執(zhí)行到“catch(ArithmeticException arithmeticException)”語句這里是運(yùn)行是異常編譯可以通過//被0除表達(dá)式以下的語句永遠(yuǎn)不會(huì)執(zhí)行inti3i1/i2;//永遠(yuǎn)不會(huì)執(zhí)行System.out.println(i3);//采用catch可以攔截異常//arithmeticException代表了一個(gè)ArithmeticException類型的局部變量//采用arithmeticException主要是來接收java異常體系給我們new的ArithmeticException對象//采用arithmeticException可以拿到更詳細(xì)的異常信息}catch(ArithmeticExceptionarithmeticException){System.out.println(被0除了);arithmeticException.printStackTrace();}}執(zhí)行結(jié)果4.1.3 異常的捕獲順序異常的捕獲一般按照由小到大的順序也就是先截獲子異常再截獲父異常以上代碼分析將IOException放到前面會(huì)出現(xiàn)編譯問題因?yàn)镮OException是FileNotFoundException的父類所以截獲了IOException異常后IOException的子異常都不會(huì)執(zhí)行到所以再次截獲FileNotFoundException沒有任何意義異常的截獲一般按照由小到大的順序也就是先截獲子異常再截獲父異常。正確的捕獲方式try{FileInputStreamfisnewFileInputStream(test.txt);fis.close();}catch(FileNotFoundExceptione){e.printStackTrace();}catch(IOExceptione){e.printStackTrace();}這里只是為了說明捕獲順序?qū)嶋H中關(guān)閉流資源fis.close()是在finally語句塊中處理的。4.2 throws拋出處理在定義方法時(shí)如果方法體中有受檢編譯時(shí)異常需要預(yù)處理可以捕獲處理也可以拋出處理。處理異常時(shí)使用throws拋出處理誰調(diào)用這個(gè)方法誰負(fù)責(zé)處理該異常在定義方法時(shí)把異常拋出就是為了提醒方法的使用者有異常需要預(yù)處理在處理異常時(shí)是選擇捕獲處理還是拋出處理一般情況下在調(diào)用其他方法時(shí)如果被調(diào)用的方法有受檢編譯時(shí)異常需要預(yù)處理選擇捕獲處理因?yàn)槟阏{(diào)用了方法 你負(fù)責(zé)處理該異常。在定義方法時(shí)如果方法體中有受檢異常需要預(yù)處理可以選擇捕獲也可以選擇拋出處理。如果方法體中通過throw語句拋出了一個(gè)異常對象所在的方法應(yīng)該使用throws聲明該異常。4.3 getMessage()和printStackTrace()如何取得異常對象的具體信息常用的方法主要有兩種獲取異常描述信息使用異常對象的getMessage()方法通常用于打印日志時(shí)取得異常的堆棧信息使用異常對象的printStackTrace()方法比較適合于程序調(diào)試階段4.4 方法覆蓋中的異常處理方法覆蓋(重寫)規(guī)則方法簽名必須相同方法名與參數(shù)列表就是方法簽名方法的返回值類型可以相同 子類方法的返回值類型也可以是父類方法返回值類型的子類型子類方法的訪問權(quán)限可以更寬泛(更大)a、如果父類方法使用public修飾子類方法只能是public修飾b、如果父類方法使用protected修飾子類方法可以是protected或者public修飾子類方法的異常要比父類方法的異常更小a、如果父類方法沒有拋出異常子類重寫后也不能拋出異常b、如果父類方法拋出了異常子類方法可以拋出相同的異常也可以拋出父類異常的子異常也可以不拋出異常代碼示例/** * 異常處理示例 * 子類方法的異常要比父類方法的異常更小 * a、如果父類方法沒有拋出異常子類重寫后也不能拋出異常 * b、如果父類方法拋出了異常子類方法可以拋出相同的異常也可以拋出父類異常的子異常也可以不拋出異常 */publicclassExceptionClass2{publicstaticvoidmain(String[]args){}classUserNotFoundExceptionextendsException{}/** * 定義一個(gè)接口里面有一個(gè)抽象login方法并且拋出了UserNotFoundException異常 */interfaceUserManager{voidlogin(Stringusername,Stringpassword)throwsUserNotFoundException;}/** * 正確寫法這里可以拋出UserNotFoundException異常也可以不拋出異常 */classUserManagerImpl1implementsUserManager{publicvoidlogin(Stringusername,Stringpassword)throwsUserNotFoundException{}}/** * 不正確因?yàn)閁serManager接口中l(wèi)ogin()方法沒有要求拋出PasswordFailureException異常 * 子類異常不能超出父類的異常范圍 */classUserManagerImpl2implementsUserManager{publicvoidlogin(Stringusername,Stringpassword)throwsUserNotFoundException,PasswordFailureException{}}/** * 正確因?yàn)镸yException是UserNotFoundException子類 * MyException異常沒有超出接口的要求 */classUserManagerImpl3implementsUserManager{publicvoidlogin(Stringusername,Stringpassword)throwsUserNotFoundException,MyException{}}classPasswordFailureExceptionextendsException{}classMyExceptionextendsUserNotFoundException{}}5 異常相關(guān)的面試題5.1 談?wù)勀鉐ava異常處理機(jī)制的理解Java對異常進(jìn)行了分類不同類型的異常分別用不同的Java類表示所有異常的根類為 java.lang.ThrowableThrowable下面又派生了兩個(gè)子類Error和Exception。Error表示應(yīng)用程序本身無法克服和恢復(fù)的一種嚴(yán)重問題。Exception表示程序還能夠克服和恢復(fù)的問題其中又分為系統(tǒng)異常和普通異常。系統(tǒng)異常系統(tǒng)異常是軟件本身缺陷所導(dǎo)致的問題也就是軟件開發(fā)人員考慮不周所導(dǎo)致的問題軟件使用者無法克服和恢復(fù)這種問題但在這種問題下還可以讓軟件系統(tǒng)繼續(xù)運(yùn)行或者讓軟件死掉例如數(shù)組下標(biāo)越界ArrayIndexOutOfBoundsException空指針異常NullPointerException、類轉(zhuǎn)換異常ClassCastException。普通異常普通異常是運(yùn)行環(huán)境的變化或異常所導(dǎo)致的問題是用戶能夠克服的問題例如網(wǎng)絡(luò)斷線硬盤空間不夠發(fā)生這樣的異常后程序不應(yīng)該死掉。Java為系統(tǒng)異常和普通異常提供了不同的解決方案編譯器強(qiáng)制普通異常必須try…catch處理或用throws聲明繼續(xù)拋給上層調(diào)用方法處理所以普通異常也稱為checked異常而系統(tǒng)異??梢蕴幚硪部梢圆惶幚硭跃幾g器不強(qiáng)制用try…catch處理或用throws聲明所以系統(tǒng)異常也稱為unchecked異常。5.2 throw 和 throws 的區(qū)別throwthrow 語句用在方法體內(nèi)表示拋出異常由方法體內(nèi)的語句處理。throw是具體向外拋出異常的動(dòng)作所以它拋出的是一個(gè)異常實(shí)例執(zhí)行throw一定是拋出了某種異常。throw一般用于拋出自定義異常。throwsthrows語句是用在方法聲明后面表示如果拋出異常由該方法的調(diào)用者來進(jìn)行異常的處理。throws主要是聲明這個(gè)方法會(huì)拋出某種類型的異常讓它的使用者要知道需要捕獲的異常的類型。throws表示出現(xiàn)異常的一種可能性并不一定會(huì)發(fā)生這種異常。5.3 final、finally、finalize 的區(qū)別final用于聲明屬性方法和類分別表示屬性不可變方法不可覆蓋被其修飾的類不可繼承。finally異常處理語句結(jié)構(gòu)的一部分表示總是執(zhí)行。finalizefinalize 是Object 類的一個(gè)方法所以Java對象都有這個(gè)方法當(dāng)某Java對象沒有更多的引用指向的時(shí)候會(huì)被垃圾回收器回收該對象被回收之前由垃圾回收器來負(fù)責(zé)調(diào)用此方法通常在該方法中進(jìn)行回收前的準(zhǔn)備工作。該方法更像是一個(gè)對象生命周期的臨終方法當(dāng)該方法被系統(tǒng)調(diào)用則代表該對象即將“死亡”但是需要注意的是我們主動(dòng)行為上去調(diào)用該方法并不會(huì)導(dǎo)致該對象“死亡”這是一個(gè)被動(dòng)的方法其實(shí)就是回調(diào)方法不需要我們調(diào)用。5.4 Java中異常分為哪些種類按照異常需要處理的時(shí)機(jī)分為編譯時(shí)異常(也叫受控異常)也叫 CheckedException和運(yùn)行時(shí)異常(也叫非受控異常)也叫 UnCheckedException。Java認(rèn)為Checked異常都是可以被處理的異常所以Java程序必須顯式處理Checked異常。如果程序沒有處理Checked 異常該程序在編譯時(shí)就會(huì)發(fā)生錯(cuò)誤無法編譯。這體現(xiàn)了Java 的設(shè)計(jì)哲學(xué)沒有完善錯(cuò)誤處理的代碼根本沒有機(jī)會(huì)被執(zhí)行。對Checked異常處理方法有兩種當(dāng)前方法知道如何處理該異常則用try…catch塊來處理該異常。當(dāng)前方法不知道如何處理則在定義該方法時(shí)聲明拋出該異常。對于運(yùn)行時(shí)異常只有當(dāng)代碼在運(yùn)行時(shí)才發(fā)行的異常編譯的時(shí)候不需要try…catch。比如除數(shù)是0和數(shù)組下標(biāo)越界等其產(chǎn)生頻繁處理麻煩若顯示申明或者捕獲將會(huì)對程序的可讀性和運(yùn)行效率影響很大。所以由系統(tǒng)自動(dòng)檢測并將它們交給缺省的異常處理程序。當(dāng)然如果你有處理要求也可以顯示捕獲它們。5.5 error和exception的區(qū)別Error類和Exception類的父類都是Throwable類他們的區(qū)別如下Error類一般是指與虛擬機(jī)相關(guān)的問題如系統(tǒng)崩潰虛擬機(jī)錯(cuò)誤內(nèi)存空間不足方法調(diào)用棧溢出等。對于這類錯(cuò)誤的導(dǎo)致的應(yīng)用程序中斷僅靠程序本身無法恢復(fù)和預(yù)防遇到這樣的錯(cuò)誤建議讓程序終止。Exception類表示程序可以處理的異??梢圆东@且可能恢復(fù)。這種異常是由與程序設(shè)計(jì)的不完善而出現(xiàn)的問題遇到這類異常應(yīng)該盡可能處理異常使程序恢復(fù)運(yùn)行而不應(yīng)該隨意終止異常。Exception類又分為未檢查異常UnCheckedException和受檢查的異常(CheckedException)。運(yùn)行時(shí)異常ArithmeticExceptionIllegalArgumentException編譯能通過但是一運(yùn)行就終止了程序不會(huì)處理運(yùn)行時(shí)異常出現(xiàn)這類異常程序會(huì)終止。而受檢查的異常要么用 try…catch 捕獲要么用throws字句聲明拋出交給它的父類處理否則編譯不會(huì)通過。5.6 說出最常見的5個(gè)RuntimeException常見的異常有java.lang.NullPointerException 空指針異常出現(xiàn)原因調(diào)用了未經(jīng)初始化的對象或者是不存在的對象java.lang.ClassCastException 數(shù)據(jù)類型轉(zhuǎn)換異常java.lang.ClassNotFoundException 指定的類找不到出現(xiàn)原因類的名稱和路徑加載錯(cuò)誤通常都是程序試圖通過字符串來加載某個(gè)類時(shí)可能引發(fā)異常java.lang.NoSuchMethodException 方法不存在異常java.lang.NumberFormatException 字符串轉(zhuǎn)換為數(shù)字異常出現(xiàn)原因字符型數(shù)據(jù)中包含非數(shù)字型字符java.lang.IndexOutOfBoundsException 數(shù)組角標(biāo)越界異常常見于操作數(shù)組對象時(shí)發(fā)生java.lang.IllegalArgumentException 方法傳遞參數(shù)錯(cuò)誤java.lang.NoClassDefFoundException 未找到類定義錯(cuò)誤SQLException SQL 異常常見于操作數(shù)據(jù)庫時(shí)的 SQL 語句錯(cuò)誤java.lang.InstantiationException 實(shí)例化異常5.7 調(diào)用下面的方法得到的返回值是什么這個(gè)問題估計(jì)大神也可能回答錯(cuò)誤。publicstaticintgetNum(){try{inta1/0;return1;}catch(Exceptione){return2;}finally{return3;}}上述代碼調(diào)用后返回的結(jié)果是3代碼分析如下publicstaticvoidmain(String[]args){//代碼走到第 3 行的時(shí)候遇到了一個(gè)MathException這時(shí)第 4 行的代碼就不會(huì)執(zhí)行了代碼直接跳轉(zhuǎn)到catch語句中走到第 6 行的時(shí)候//異常機(jī)制有一個(gè)原則如果在catch中遇到了return或者異常等能使該函數(shù)終止的話那么有finally就必須先執(zhí)行完finally代碼塊里面的代碼然后再返回值。//因此代碼又跳到第 8 行可惜第 8 行是一個(gè)return語句那么這個(gè)時(shí)候方法就結(jié)束了因此第 6 行的返回結(jié)果就無法被真正返回。//如果finally僅僅是處理了一個(gè)釋放資源的操作那么該道題最終返回的結(jié)果就是2因此上面這道題返回值是3。System.out.println(getNum());}注只有在 try 里面通過 System.exit(0) 來退出 JVM 的情況下 finally 塊中的代碼才不會(huì)執(zhí)行其他 return 等情況都會(huì)執(zhí)行finally 代碼塊。5.8 java 中如何編寫自定義異常自定義異常通常繼承于Exception或RuntimeException到底繼承那個(gè)應(yīng)該看具體情況來定。自定義異常類可以有自己的變量和方法來傳遞錯(cuò)誤代碼或傳遞其它異常相關(guān)信息。實(shí)際工作中都會(huì)自定義異常類來處理異常。自定義受控異常/** * 自定義受控異常編譯時(shí)、檢查時(shí)異常checkedException繼承Exception */classMyCheckedExceptionextendsException{publicMyCheckedException(){//調(diào)用父類的默認(rèn)構(gòu)造函數(shù)super();}publicMyCheckedException(Stringmessage){//手動(dòng)調(diào)用父類的構(gòu)造方法super(message);}}自定義非受控異常/** * 自定義非受控異常運(yùn)行時(shí)異常-unCheckedException */classMyRuntimeExceptionextendsRuntimeException{publicMyRuntimeException(){//調(diào)用父類的默認(rèn)構(gòu)造函數(shù)super();}publicMyRuntimeException(Stringmessage){//手動(dòng)調(diào)用父類的構(gòu)造方法super(message);}}使用自定義異常/** * 使用自定義異常 */publicclassMyExceptionClass{publicstaticvoidmain(String[]args){testException1();testException2();}privatestaticvoidtestException1(){//【示例代碼】自定義受控異常的使用try{method1(10,0);}catch(MyCheckedExceptione){//必須攔截,攔截后建議給出處理如果不給出處理就屬于隱藏了該異常//系統(tǒng)將不給出任何提示使程序的調(diào)試非常困難System.out.println(e.getMessage());}}privatestaticvoidtestException2(){method2(10,0);}/** * 自定義受控異常的使用 * 如果是受控異常必須throws聲明讓調(diào)用方處理異常 * * param value1 * param value2 * throws MyCheckedException */privatestaticvoidmethod1(intvalue1,intvalue2)throwsMyCheckedException{if(value20){thrownewMyCheckedException(方法1自定義受控異常除數(shù)不能為0);}intvalue3value1/value2;System.out.println(value3);}/** * 【示例代碼】自定義非受控異常的使用 * * param value1 * param value2 */privatestaticvoidmethod2(intvalue1,intvalue2){//throws MyRuntimeException {if(value20){//拋出非受控異常方法可以不使用throws進(jìn)行聲明但也可以顯示的聲明thrownewMyRuntimeException(方法2自定義非受控異常除數(shù)不能為0);}intvalue3value1/value2;System.out.println(value3);}}執(zhí)行結(jié)果6 總結(jié)本文主要對Java中的異常相關(guān)的知識(shí)進(jìn)行了一下總結(jié)。異常的分類受控異常和非受控異常的區(qū)別異常的捕獲和拋出處理異常的捕獲順序先捕獲小的再捕獲大的方法覆蓋和異常的關(guān)系異常的5個(gè)關(guān)鍵字try、catch、finally、throws、throw最后上一個(gè)異常的圖來總結(jié)下Java中的異常如下圖所示寫博客是為了記住自己容易忘記的東西另外也是對自己工作的總結(jié)希望盡自己的努力做到更好大家一起努力進(jìn)步如果有什么問題歡迎大家一起探討代碼如有問題歡迎各位大神指正給自己的夢想添加一雙翅膀讓它可以在天空中自由自在的飛翔