異常:異常是指中斷程序正常執(zhí)行的一種指令流
?在JAVA程序中一旦出現(xiàn)了異常,而程序又沒(méi)有及時(shí)處理的情況下穆端,那么程序會(huì)中斷執(zhí)行袱贮。
例如,觀察以下的代碼:
public class Demo22{
?public static void main(String args[]){
?int i = 10 ;
?int j = 0 ;
?System.out.println(" ---------?計(jì)算開(kāi)始?---------") ;
?System.out.println("i / j = " + (i / j)) ;?à?此段代碼出現(xiàn)了異常
?System.out.println(" ---------?計(jì)算結(jié)束?---------") ;
?}
};
?以上代碼編譯的時(shí)候不存在任何的問(wèn)題体啰,那么執(zhí)行時(shí)攒巍,出錯(cuò)了荒勇,打印內(nèi)容如下:
---------?計(jì)算開(kāi)始?---------
Exception in thread "main" java.lang.ArithmeticException: / by zero
?at Demo22.main(Demo22.java:6)
?整個(gè)程序,在出現(xiàn)異常的代碼之后不再被執(zhí)行了卷玉,異常之前的程序呢品姓?正確的執(zhí)行了衬潦。
?那么在JAVA中我們所處理的異常都屬于運(yùn)行時(shí)異常,即:執(zhí)行JAVA程序的時(shí)候出現(xiàn)的錯(cuò)誤,那么實(shí)際上對(duì)于JAVA的異常分類應(yīng)該按如下的形式劃分:
?ArithmeticException?à?RuntimeException?à?Exception(往往是要由用戶自己處理的)
?所以對(duì)于異常而言耻瑟,它是一個(gè)統(tǒng)稱谆构,代表了:
?Throwable(可能的拋出)
|-?Exception:表示需要人為處理的異常蔗蹋,指的是程序的錯(cuò)誤?à?因?yàn)槌绦虻腻e(cuò)誤較多妥衣,所以就習(xí)慣了把所有的錯(cuò)誤都統(tǒng)一成為異常蜂筹。
?|- Error:表示JVM錯(cuò)誤,人為不能處理
異常的處理格式如下:
try{
?包含可能出現(xiàn)錯(cuò)誤的代碼段?;
}catch(出錯(cuò)的類型?出錯(cuò)的對(duì)象){
?對(duì)于錯(cuò)誤的處理語(yǔ)句?;
}
?那么使用如上的格式修改之前的代碼口蝠,保證程序可以正確的執(zhí)行完:
public class Demo23{
?public static void main(String args[]){
?int i = 10 ;
?int j = 0 ;
?System.out.println(" ---------?計(jì)算開(kāi)始?---------") ;
?try{
?System.out.println("i / j = " + (i / j)) ;
?}catch(ArithmeticException e){
?System.out.println("計(jì)算出現(xiàn)了錯(cuò)誤。。。") ;
?}
?System.out.println(" ---------?計(jì)算結(jié)束?---------") ;
?}
};
?但是以上的程序依然存在了些小小的問(wèn)題,例如:對(duì)于計(jì)算蹈集,往往應(yīng)該由用戶自己輸入數(shù)據(jù),所以此時(shí)可以通過(guò)接收參數(shù)為其輸入數(shù)據(jù)雇初。代碼如下:
public class Demo24{
?public static void main(String args[]){
?int i = 10 ;
?int j = 0 ;
?System.out.println(" ---------?計(jì)算開(kāi)始?---------") ;
?try{
?i = Integer.parseInt(args[0]) ;
?j = Integer.parseInt(args[1]) ;
?System.out.println("i / j = " + (i / j)) ;
?}catch(ArithmeticException e){
?System.out.println("計(jì)算出現(xiàn)了錯(cuò)誤拢肆。。靖诗。") ;
?}
?System.out.println(" ---------?計(jì)算結(jié)束?---------") ;
?}
};
?如果現(xiàn)在輸入的內(nèi)容是正確的數(shù)字郭怪,則程序不會(huì)有任何的問(wèn)題,但是既然數(shù)據(jù)是由用戶自己輸入的刊橘,那么肯定會(huì)輸入各種違法的數(shù)據(jù)鄙才。
?存在的問(wèn)題:
?·?不輸入任何參數(shù),出現(xiàn)數(shù)組越界:ArrayIndexOutOfBoundsException
?·?輸入的參數(shù)不是數(shù)字促绵,出現(xiàn)了數(shù)字格式轉(zhuǎn)換錯(cuò)誤:NumberFormatException
?·?輸入的被除數(shù)是0攒庵,出現(xiàn)算術(shù)錯(cuò)誤:ArithmeticException
?在以上的錯(cuò)誤之中嘴纺,只有算術(shù)錯(cuò)誤被處理了,因?yàn)樵诔绦蛏暇邆淞怂阈g(shù)錯(cuò)誤的處理能力浓冒。那么也就意味著栽渴,現(xiàn)在的異常處理并不完善,需要加入更多的處理稳懒,所以需要編寫(xiě)更多的catch熔萧。
?以上的程序修改為:
public class Demo24{
?public static void main(String args[]){
?int i = 10 ;
?int j = 0 ;
?System.out.println(" ---------?計(jì)算開(kāi)始?---------") ;
?try{
?i = Integer.parseInt(args[0]) ;
?j = Integer.parseInt(args[1]) ;
?System.out.println("i / j = " + (i / j)) ;
?}catch(ArithmeticException e){
?System.out.println("算術(shù)錯(cuò)誤。僚祷。佛致。"+e) ;
?}
?catch(ArrayIndexOutOfBoundsException e){
?System.out.println("沒(méi)有輸入?yún)?shù)。辙谜。俺榆。"+e) ;
?}
?catch(NumberFormatException e){
?System.out.println("輸入的內(nèi)容不是數(shù)字。装哆。罐脊。"+e) ;
?}
?System.out.println(" ---------?計(jì)算結(jié)束?---------") ;
?}
};
?但是會(huì)發(fā)現(xiàn)比較麻煩,因?yàn)楝F(xiàn)在已經(jīng)知道了的是三個(gè)錯(cuò)誤蜕琴,那么對(duì)于很多未知道的錯(cuò)誤呢萍桌?那么此時(shí),就需要分析異常的產(chǎn)生過(guò)程凌简。
?發(fā)現(xiàn)catch中接收的內(nèi)容都是對(duì)象上炎,那么也就意味著,所謂的異常雏搂,就是自動(dòng)產(chǎn)生了一個(gè)異常類的實(shí)例化對(duì)象藕施。一出錯(cuò)就產(chǎn)生。
?對(duì)象有一個(gè)特點(diǎn)凸郑,可以向上自動(dòng)轉(zhuǎn)型裳食,Exception是用戶需要處理的最大異常,那么證明所有的對(duì)象都可以向Exception轉(zhuǎn)換芙沥。
public class Demo25{
?public static void main(String args[]){
?int i = 10 ;
?int j = 0 ;
?System.out.println(" ---------?計(jì)算開(kāi)始?---------") ;
?try{
?i = Integer.parseInt(args[0]) ;
?j = Integer.parseInt(args[1]) ;
?System.out.println("i / j = " + (i / j)) ;
?}catch(ArithmeticException e){
?System.out.println("算術(shù)錯(cuò)誤诲祸。。而昨。"+e) ;
?}
?catch(ArrayIndexOutOfBoundsException e){
?System.out.println("沒(méi)有輸入?yún)?shù)救氯。。配紫。"+e) ;
?}
?catch(NumberFormatException e){
?System.out.println("輸入的內(nèi)容不是數(shù)字径密。。躺孝。"+e) ;
?}
?catch(Exception e){
?System.out.println("其他異常享扔。底桂。。"+e) ;
?}
?System.out.println(" ---------?計(jì)算結(jié)束?---------") ;
?}
};
注意:
?如果在程序中出現(xiàn)了多個(gè)catch語(yǔ)句惧眠,則捕獲更粗的catch要放在捕獲更細(xì)的catch之后籽懦。
public class Demo25{
?public static void main(String args[]){
?int i = 10 ;
?int j = 0 ;
?System.out.println(" ---------?計(jì)算開(kāi)始?---------") ;
?try{
?i = Integer.parseInt(args[0]) ;
?j = Integer.parseInt(args[1]) ;
?System.out.println("i / j = " + (i / j)) ;
?}catch(Exception e){
?System.out.println("其他異常。氛魁。暮顺。"+e) ;
?}catch(ArithmeticException e){
?System.out.println("算術(shù)錯(cuò)誤。秀存。捶码。"+e) ;
?}catch(ArrayIndexOutOfBoundsException e){
?System.out.println("沒(méi)有輸入?yún)?shù)。或链。惫恼。"+e) ;
?}catch(NumberFormatException e){
?System.out.println("輸入的內(nèi)容不是數(shù)字。澳盐。祈纯。"+e) ;
?}
?System.out.println(" ---------?計(jì)算結(jié)束?---------") ;
?}
};
?則編譯的時(shí)候出現(xiàn)了以下的錯(cuò)誤,說(shuō)是許多的異常已經(jīng)被捕獲了叼耙。
Demo25.java:14:?已捕捉到異常?java.lang.ArithmeticException
?catch(ArithmeticException e){
?^
Demo25.java:17:?已捕捉到異常?java.lang.ArrayIndexOutOfBoundsException
?catch(ArrayIndexOutOfBoundsException e){
?^
Demo25.java:20:?已捕捉到異常?java.lang.NumberFormatException
?catch(NumberFormatException e){
?^
3?錯(cuò)誤
?既然所有異常類的對(duì)象都可以向Exception轉(zhuǎn)換腕窥,那么是不是直接使用Exception接收更方便?
public class Demo26{
?public static void main(String args[]){
?int i = 10 ;
?int j = 0 ;
?System.out.println(" ---------?計(jì)算開(kāi)始?---------") ;
?try{
?i = Integer.parseInt(args[0]) ;
?j = Integer.parseInt(args[1]) ;
?System.out.println("i / j = " + (i / j)) ;
?System.out.println("***************************") ;
?}catch(Exception e){
?System.out.println(e) ;
?}
?System.out.println(" ---------?計(jì)算結(jié)束?---------") ;
?}
};
?以上是異常處理的一種格式筛婉,實(shí)際上異常處理還有另外一種格式簇爆,就是說(shuō),可以為異常做一個(gè)統(tǒng)一的出口倾贰,不管是否發(fā)生了異常冕碟,都要執(zhí)行此代碼:
try{
?包含可能出現(xiàn)錯(cuò)誤的代碼段?;
}catch(出錯(cuò)的類型?出錯(cuò)的對(duì)象){
?對(duì)于錯(cuò)誤的處理語(yǔ)句?;
}finally{
?不管是否出現(xiàn)異常,都執(zhí)行此代碼?;
}
?代碼如下:
public class Demo27{
?public static void main(String args[]){
?int i = 10 ;
?int j = 0 ;
?System.out.println(" ---------?計(jì)算開(kāi)始?---------") ;
?try{
?i = Integer.parseInt(args[0]) ;
?j = Integer.parseInt(args[1]) ;
?System.out.println("i / j = " + (i / j)) ;
?}catch(Exception e){
?System.out.println(e) ;
?}finally{?à?典型的程序出口
?System.out.println("不管是否存在異常匆浙,此代碼都會(huì)被執(zhí)行。厕妖。首尼。") ;
?}
?System.out.println(" ---------?計(jì)算結(jié)束?---------") ;
?}
};
在異常處理中還有兩個(gè)很重要的關(guān)鍵字
?·?throws:在方法的聲明處使用,表示此方法不處理異常言秸,而交給被調(diào)用處處理软能。
?·?throw:表示人為的拋出一個(gè)異常。
例如:定義一個(gè)數(shù)學(xué)類举畸,里面有一個(gè)除法
class Math{
?//?此代碼有可能發(fā)生問(wèn)題查排,也有可能不發(fā)生問(wèn)題
?//?一旦發(fā)生問(wèn)題,找調(diào)用處抄沮,誰(shuí)調(diào)用的此方法跋核,誰(shuí)去處理
?public int div(int i,int j) throws Exception{
?return i / j ;
?}
};
public class Demo28{
?public static void main(String args[]){
?Math m = new Math() ;
?System.out.println(m.div(10,2)) ;
?}
};
?按規(guī)定來(lái)說(shuō)岖瑰,此方法在調(diào)用的時(shí)候使用異常的捕獲,如果不使用砂代,則編譯時(shí)出現(xiàn)以下的錯(cuò)誤提示:
Demo28.java:11:?未報(bào)告的異常?java.lang.Exception蹋订;必須對(duì)其進(jìn)行捕捉或聲明以便拋出
?System.out.println(m.div(10,2)) ;
?^
1?錯(cuò)誤
?所以對(duì)于調(diào)用有throws聲明的方法,必須使用try…catch:
class Math{
?//?此代碼有可能發(fā)生問(wèn)題刻伊,也有可能不發(fā)生問(wèn)題
?//?一旦發(fā)生問(wèn)題露戒,找調(diào)用處,誰(shuí)調(diào)用的此方法捶箱,誰(shuí)去處理
?public int div(int i,int j) throws Exception{
?return i / j ;
?}
};
public class Demo28{
?public static void main(String args[]){
?Math m = new Math() ;
?try{
?System.out.println(m.div(10,0)) ;
?}catch(Exception e){
?System.out.println(e) ;
?}
?}
};
?問(wèn)智什?既然main方法是一個(gè)方法,那么能不能在主方法上編寫(xiě)throws語(yǔ)句呢丁屎?肯定是可以的
class Math{
?//?此代碼有可能發(fā)生問(wèn)題撩鹿,也有可能不發(fā)生問(wèn)題
?//?一旦發(fā)生問(wèn)題,找調(diào)用處悦屏,誰(shuí)調(diào)用的此方法节沦,誰(shuí)去處理
?public int div(int i,int j) throws Exception{
?return i / j ;
?}
};
public class Demo29{
?public static void main(String args[]) throws Exception{
?Math m = new Math() ;
?System.out.println(m.div(10,0)) ;
?}
};
?觀察錯(cuò)誤的提示:
Exception in thread "main" java.lang.ArithmeticException: / by zero
?at Math.div(Demo29.java:5)
?at Demo29.main(Demo29.java:11)
?可以發(fā)現(xiàn)以上的錯(cuò)誤提示與不使用try…catch效果是一樣的,證明所有的錯(cuò)誤都交給了JVM進(jìn)行處理础爬,實(shí)際上在JAVA中默認(rèn)的處理方式也就是使用JVM完成甫贯。
?throw:表示在程序中人為的拋出一個(gè)異常,而且必須使用try…catch進(jìn)行處理看蚜。
public class Demo30{
?public static void main(String args[]){
?try{
?throw new Exception("我自己樂(lè)意拋叫搁。。供炎。") ;
?}catch(Exception e){
?System.out.println(e) ;
?}
?}
};
?因?yàn)閷?duì)于異常而言渴逻,最終結(jié)果肯定都是拋出一個(gè)異常的實(shí)例化對(duì)象。所以是自己拋還是系統(tǒng)拋都肯定需要進(jìn)行異常的捕獲及處理音诫。
?設(shè)計(jì)一個(gè)除法操作惨奕,在操作之前編寫(xiě):計(jì)算開(kāi)始,在操作之后編寫(xiě)計(jì)算結(jié)束竭钝,中間不管是否出現(xiàn)了錯(cuò)誤梨撞,都要打印這樣兩句話,問(wèn):該如何實(shí)現(xiàn)香罐?
class Math{
?public int div(int i,int j) throws Exception{
?System.out.println(" ========?計(jì)算開(kāi)始?=========") ;
?int temp = 0 ;
?try{
?temp = i / j ;
?}catch(Exception e){
?throw e ;
?}finally{
?System.out.println(" ========?計(jì)算結(jié)束?=========") ;
?}
?return temp ;
?}
};
public class Demo31{
?public static void main(String artgs[]){
?Math m = new Math() ;
??try{
?System.out.println(m.div(1,0)) ;
?}catch(Exception e){
?System.out.println(e) ;
?}
?}
};
?一般而言卧波,對(duì)于throw、throws庇茫、finally往往會(huì)一起使用港粱。
自定義異常:
?一個(gè)類只要繼承了Exception就可以稱為一個(gè)異常類。
class MyException extends Exception{
?public MyException(String msg){
?super(msg) ;
?}
};
public class Demo32{
?public static void main(String args[]){
?try{
?throw new MyException("自己定義玩的旦签。查坪。") ;
?}catch(Exception e){
?System.out.println(e) ;
?}
?}
};
注意點(diǎn):
?·?throw與throws的區(qū)別寸宏?
?|- throw:是人為拋出異常
?|- throws:方法聲明處使用,表示在方法中不處理異常
?·?final與finally
?|- final:定義類咪惠、方法击吱、常量
?|- finally:異常的統(tǒng)一出口
寫(xiě)在最后:
碼字不易看到最后了,那就點(diǎn)個(gè)關(guān)注唄遥昧,只收藏不點(diǎn)關(guān)注的都是在耍流氓覆醇!
關(guān)注并私信我“架構(gòu)”,免費(fèi)送一些Java架構(gòu)資料炭臭,先到先得永脓!