黑马程序员_java异常处理机制
?
java異常處理機(jī)制
1:什么是異常?
異常(Exception)也叫例外。在Java編程語(yǔ)言中,異常就是程序在運(yùn)行過(guò)程中由于硬件設(shè)備問(wèn)題、軟件設(shè)計(jì)錯(cuò)誤、缺陷等導(dǎo)致的程序錯(cuò)誤。在軟件開發(fā)過(guò)程中,很多情況都將導(dǎo)致異常的產(chǎn)生,例如:
(1)?想打開的文件不存在;
(2)?網(wǎng)絡(luò)連接中斷;
(3)?操作數(shù)超出預(yù)定范圍;
(4)?正在裝載的類文件丟失;
(5)?訪問(wèn)的數(shù)據(jù)庫(kù)打不開;
可見(jiàn),在程序中產(chǎn)生異常的現(xiàn)象是非常普遍的。在Java編程語(yǔ)言中,對(duì)異常的處理有非常完備的機(jī)制。異常本身作為一個(gè)對(duì)象,產(chǎn)生異常就是產(chǎn)生一個(gè)異常對(duì)象。這個(gè)對(duì)象可能由應(yīng)用程序本身產(chǎn)生,也?
可能由?Java?虛擬機(jī)產(chǎn)生,這取決于產(chǎn)生異常的類型。該異常對(duì)象中包括了異常事件的類型以及發(fā)生異常時(shí)應(yīng)用程序目前的狀態(tài)和調(diào)用過(guò)程。請(qǐng)看下面產(chǎn)生異常的例子
文件操作將產(chǎn)生異常
//?Exception1.java
import?java.io.*;
class?Exception1?{
?p?lic?static?void?main(String?args[]){
??FileInputStream?fis?=new??FileInputStream("text.txt");
??int?b;
??while((b=fis.read())!=-1)?{
???System.out.print(b);
??}
??fis.close();
?}
}
當(dāng)編譯這個(gè)程序時(shí),屏幕上會(huì)輸出下面的信息:
D:\user\chap08>javac?Exception1.java
Exception1.java:5:?unreported?exception?java.io.FileNotFoundException;?must?be?caught?or?declared?to?be?thrown
??FileInputStream?fis?=?new??FileInputStream("text.txt");
^
Exception1.java:7:?unreported?exception?java.io.IOException;?must?be?caught?or?declared?to?be?thrown
??while((b=fis.read())!=-1)?{
???^
Exception1.java:10:?unreported?exception?java.io.IOException;?must?be?caught?ordeclared?to?be?thrown
???fis.close();
^
3?errors
數(shù)組下標(biāo)超界的例子
//Exception2.java
p?lic?class?Exception2{
?p?lic?static?void?main?(String?args[])?{?
??String?langs?[]?=?{"Java","Visaul?Basic","C++"};
??int?i?=?0;
??while?(i?<?4)?{
???System.out.println?(langs[i]);
???i++;
??}
?}
}?
程序的編譯和運(yùn)行結(jié)果如下:
D:\user\chap08>javac?Exception2.java??
D:\user\chap08>java??Exception2
Java
Visaul?Basic
C++
Exception?in?thread?"main"?java.lang.ArrayIndexOutOfBoundsException:?3
at?Exception2.main(Exception2.java:8)
上面的例子編譯可以通過(guò),但運(yùn)行時(shí)出現(xiàn)異常信息被拋出。在其循環(huán)被
執(zhí)行四次之后,數(shù)組下標(biāo)溢出,程序終止,并帶有錯(cuò)誤信息,就象前面
所示的程序那樣。
被0除的例子
//?Exception3.java
class?Exception3{
??p?lic?static?void?main(String?args[]){
int?a=0;
System.out.println(5/a);
??}
}
我們編譯這個(gè)程序得到其字節(jié)碼文件,然后運(yùn)行它,屏幕上的顯示如
下:
D:\user\chap08>javac?Exception3.java
D:\user\chap08>java??Exception3
Exception?in?thread?"main"?java.lang.ArithmeticException:?/?by?zero
at?Exception3.main(Exception3.java:5)
因?yàn)槌龜?shù)不能為0,所以在程序運(yùn)行的時(shí)候出現(xiàn)了除以0溢出的異常事
件。
在上面的三個(gè)例子中,我們都遇到了異常。屏幕上所顯示的信息
java.io.IOException、
java.io.FileNotFoundException、
java.lang.ArrayIndexOutOfBoundsException
以及java.lang.ArithmeticException
分別指明了異常的類型以及異常所在的包。同時(shí)我們也可以看到,對(duì)
于某些異常,在程序中必須對(duì)它進(jìn)行處理,否則編譯程序會(huì)指出錯(cuò)誤
(如例1)。但對(duì)另一些異常,在程序中可以不做處理,而直接由運(yùn)行時(shí)
系統(tǒng)來(lái)處理(如例3)。在下節(jié)中,我們將詳細(xì)了解這兩類異常,以及在
程序中如何處理這兩類異常。?
2?異常處理機(jī)制
(1)Java的異常處理機(jī)制:
在?Java?程序的執(zhí)行過(guò)程中,如果出現(xiàn)了異常事件,就會(huì)生成一個(gè)異常對(duì)象。這個(gè)對(duì)象可能是由正在運(yùn)行的方法生成,也可能由Java虛擬機(jī)生成,其中包含一些信息指明異常事件的類型以及當(dāng)異常發(fā)生
時(shí)程序的運(yùn)行狀態(tài)等。Java語(yǔ)言提供兩種處理異常的機(jī)制:
(1)捕獲異常
在Java程序運(yùn)行過(guò)程中系統(tǒng)得到一個(gè)異常對(duì)象時(shí),它將會(huì)沿著方法的調(diào)用棧逐層回溯,尋找處理這一異常的代碼。找到能夠處理這種類型異常的方法后,運(yùn)行時(shí)系統(tǒng)把當(dāng)前異常對(duì)象交給這個(gè)方法進(jìn)行處
理,這一過(guò)程稱為捕獲(catch)異常。這是一種積極的異常處理機(jī)制。如果Java運(yùn)行時(shí)系統(tǒng)找不到可以捕獲異常的方法,則運(yùn)行時(shí)系統(tǒng)將終止,相應(yīng)的Java程序也將退出。
(2)聲明拋棄異常
當(dāng)Java程序運(yùn)行時(shí)系統(tǒng)得到一個(gè)異常對(duì)象時(shí),如果一個(gè)方法并不知道如何處理所出現(xiàn)的異常,則可在方法聲明時(shí),聲明拋棄(throws)異常。
(2)異常類的類層次:
?前面已經(jīng)提到,Java?是采用面向?qū)ο蟮姆椒▉?lái)處理錯(cuò)誤的,一個(gè)異常事件
是由一個(gè)異常對(duì)象來(lái)代表的。這些異常對(duì)象都對(duì)應(yīng)于類java.lang.Throwable及
其子類。下面我們就來(lái)看一下異常類的層次。
?在?java類庫(kù)的每個(gè)包中都定義了自己的異常類,所有這些類都直接或間接
地繼承于類Throwable。圖1列舉了一些異常類并指明了它們的繼承關(guān)系。
?Java中的異常事件分為兩大類。一類繼承于類Error,它的繼承關(guān)系如下:
?java.lang.Object
?java.lang.Throwable?
?java.lang.Error
?常見(jiàn)的錯(cuò)誤類有AnnotationFormatError,??AssertionError,??AWTError,??
LinkageError,?CoderMalfunctionError,?FactoryConfigurationError,ThreadDeath,
Virt?lMachineError,??TransformerFactoryConfigurationError等,包括動(dòng)態(tài)鏈接
失敗、線程死鎖、圖形界面錯(cuò)誤、虛擬機(jī)錯(cuò)誤等,通常Java程序不應(yīng)該捕獲這
類異常,也不會(huì)拋棄這種異常。
另外一類異常則繼承于類Exception,這是Java程序中所大量處理的異常。它
的繼承關(guān)系如下:
java.lang.Object
?java.lang.Throwable
??java.lang.Exception
常見(jiàn)異常類有:AclNotFoundException,?ApplicationException,?AWTException,?
BackingStoreException,?ClassNotFoundException,?
CloneNotSupportedException,?DataFormatException,?DestroyFailedException,?
ExecutionException,?PrintException,?GeneralSecurityException,?
InterruptedException,?InvalidPreferencesFormatException,??ParseException,?
RuntimeException,?SAXException,?SQLException,?TimeoutException,?
TransformerException,?UnsupportedCallbackException,?
UnsupportedLookAndFeelException,?URISyntaxException,?UserException,?
XAException,?XMLParseException,?XPathException??等
其中包括了運(yùn)行時(shí)異常和非運(yùn)行時(shí)異常。?
常見(jiàn)的運(yùn)行時(shí)異常如下:
(1)?類型轉(zhuǎn)換異常ClassCastException
String?strName=new?string(“123”);
int?nNumber=(int)strName;??
(2)?數(shù)組超界異常ArrayIndexOutBoundsException
int[]?b=new?int[10];
b[10]=1000;
(3)?指定數(shù)組維數(shù)為負(fù)值異常NegativeArraySizeException
b[-1]=1001;
(4)?算術(shù)異常ArithmeticException
int?b=0;
a=500/b;
(5)?Java系統(tǒng)內(nèi)部異常InternalException
JVM拋出的異常。
(6)?類型不符合異常IncompatibleTypeException
int?n=12345;
String?s=(String)n;??
(7)?內(nèi)存溢出異常OutOfMemeoryException
(8)?沒(méi)有找到類定義異常NoClassDefFoundException
aClass?aa=new?aClas();?//但aClass類未定義。
(9)?空指針異常?NullPointerException
int?b[?];
b[0]=99;???//沒(méi)有實(shí)例化,就訪問(wèn),將產(chǎn)生空指針。
常見(jiàn)的非運(yùn)行時(shí)異常如下:
(1)?ClassNotFoundException?:找不到類或接口所產(chǎn)生的異常
(2)?CloneNotSupportedException:使用對(duì)象的?clone?方法但無(wú)法執(zhí)行?Cloneable?所產(chǎn)生的異常。
(3)?IllegalAccessException?:類定義不明確所產(chǎn)生的異常。例如:類不為?p?lic?,或是包含一個(gè)類定義在另一個(gè)類庫(kù)內(nèi)。
(4)?IOException?:在一般情況下不能完成I/O操作所產(chǎn)生的異常。
(5)?EOFException:?打開文件沒(méi)有數(shù)據(jù)可以讀取所產(chǎn)生的異常
(6)?FileNotFoundException?:在文件系統(tǒng)中,找不到文件名稱或路徑所產(chǎn)生
(7)?InterruptedIOException:目前線程等待執(zhí)行,另一線程中斷目前線程I/O運(yùn)行所產(chǎn)生的異常
??在Sun公司提供的各種API包中,如java.io,java.net,java.awt等,都提供不同情況下可能產(chǎn)生的異常。由于異常的種類非常多,需要讀者實(shí)際運(yùn)用中逐漸掌握。?
(3)Throwable類的常用方法:
java.lang.Throwable類是所有Error類和Exception類的父類,常用的方法有?:fillInStackTrace()?、getLocalizedMessage()?、getMessage()?、printStackTrace()、printStackTrace(PrintStream)?
、?????????????printStackTrace(PrintWriter)?、toString()。
(1)?p?lic?native?Throwable?fillInStackTrace()
填寫執(zhí)行堆棧跟蹤信息。?該方法在應(yīng)用程序重新拋出錯(cuò)誤或異常時(shí)有用。例如:?
?try?{
?a?=?b?/?c;
?}?catch(ArithmeticThrowable?e)?{
?a?=?Number.MAX_VAL;
?throw?e.fillInStackTrace();
?}
(2)?p?lic?String?getLocalizedMessage()
生成該?Throwable?的本地化描述。?子類可能會(huì)覆蓋該方法以便產(chǎn)生一個(gè)特定于本地的消息。?對(duì)于未覆蓋該方法的子類,缺省地返回調(diào)用?getMessage()?的結(jié)果。?
(3)?p?lic?String?getMessage()
返回該?throwable?對(duì)象的詳細(xì)信息。如果該對(duì)象沒(méi)有詳細(xì)信息則返回null。?
(4)?p?lic?void?printStackTrace()
把該?Throwable?和它的跟蹤情況打印到標(biāo)準(zhǔn)錯(cuò)誤流。
(5)?p?lic?void?printStackTrace(PrintStream?s)
把該?Throwable?和它的跟蹤情況打印到指定打印流。?
(6)?p?lic?void?printStackTrace(PrintWriter?s)
把該?Throwable?和它的跟蹤情況打印到指定打印流。
(7)?p?lic?String?toString()
返回該?throwable?對(duì)象的簡(jiǎn)短字符串描述。?
3?異常的處理
(1)捕獲異常try-catch-finally:
一個(gè)方法中如果對(duì)某種類型的異常對(duì)象提供了相應(yīng)的處理代碼,則這個(gè)方法可捕獲該種異常。捕獲異常是通過(guò)try-catch-finally語(yǔ)句實(shí)現(xiàn)的。其語(yǔ)法為:
try{ ??...... }catch(?ExceptionName1?e?){ ......? }catch(?ExceptionName2?e?){ ...... } ...... }finally{ ...... }
1、try
捕獲異常的第一步是用try{…}選定捕獲異常的范圍,由try所限定的代碼塊中的語(yǔ)句在執(zhí)行過(guò)程中可能會(huì)生成異常對(duì)象并拋棄。
2、catch
每個(gè)try代碼塊可以伴隨一個(gè)或多個(gè)catch語(yǔ)句,用于處理try代碼塊中所生成的異常事件。catch語(yǔ)句只需要一個(gè)形式參數(shù)來(lái)指明它所能夠捕獲的異常類型,這個(gè)類必須是Throwable的子類,運(yùn)行時(shí)系統(tǒng)通過(guò)
參數(shù)值把被拋棄的異常對(duì)象傳遞給catch塊。
catch塊中的代碼用來(lái)對(duì)異常對(duì)象進(jìn)行處理,與訪問(wèn)其它對(duì)象一樣,可以訪問(wèn)一個(gè)異常對(duì)象的變量或調(diào)用它的方法。getMessage(?)是類Throwable所提供的方法,用來(lái)得到有關(guān)異常事件的信息,類
Throwable還提供了方法printStackTrace(?)用來(lái)跟蹤異常事件發(fā)生時(shí)執(zhí)行堆棧的內(nèi)容。例如:
try{ ...... }
?catch(?FileNotFoundException?e?)
?{
??System.out.println(?e?);
??System.out.println(?"message:?"+e.getMessage()?
?);
??e.printStackTrace(?System.out?);
?}catch(?IOException?e?)
?{
??System.out.println(?e?);
?}
3、catch?語(yǔ)句的順序 捕獲異常的順序和catch語(yǔ)句的順序有關(guān),當(dāng)捕獲到一個(gè)異常時(shí),剩下的catch語(yǔ)句就不再進(jìn)行匹配。因此,在安排catch語(yǔ)句的順序時(shí),首先應(yīng)該捕獲最特殊的異常,然后再逐漸
一般化。也就是一般先安排子類,再安排父類。例如上面的程序如果安排成如下的形式:
try{ ...... }
?catch(IOException?e?)
?{
??System.out.println(?e?);
??System.out.println(?"message:?"+e.getMessage()?);
??e.printStackTrace(?System.out?);
?}catch(FileNotFoundException?e?)
?{
??System.out.println(?e?);
?}
由于第一個(gè)catch語(yǔ)句首先得到匹配,第二個(gè)catch語(yǔ)句將不會(huì)被執(zhí)行。編譯時(shí)將出現(xiàn)“catch?not?reached”的錯(cuò)誤。
4、finally
捕獲異常的最后一步是通過(guò)finally語(yǔ)句為異常處理提供一個(gè)統(tǒng)一的出口,使得在控制流轉(zhuǎn)到程序的其它部分以前,能夠?qū)Τ绦虻臓顟B(tài)作統(tǒng)一的管理。一般是用來(lái)關(guān)閉文件或釋放其他的系統(tǒng)資源。雖然
finally作為try-catch-finally結(jié)構(gòu)的一部分,但在程序是可選的,也就是說(shuō)可以沒(méi)有?finally語(yǔ)句。如果存在finally語(yǔ)句,不論try塊中是否發(fā)生了異常,是否執(zhí)行過(guò)catch?語(yǔ)句,都要執(zhí)行finally語(yǔ)
句。
另外,try-catch-finally可以嵌套。
(2)聲明拋出異常:
如果在一個(gè)方法中生成了一個(gè)異常,但是這一方法并不確切地知道該如何對(duì)這一異常事件進(jìn)行處理,這時(shí),該方法就應(yīng)該聲明拋棄異常,使得異常對(duì)象可以從調(diào)用棧向后傳播,直到有合適的方法捕獲它
為止。?????聲明拋棄異常是在一個(gè)方法聲明中的throws子句中指明的。例如: p?lic?int?read?()?throws?IOException{ ……
??}
??throws子句中同時(shí)可以指明多個(gè)異常,之間由逗號(hào)隔開。例如:?
??p?lic?static?void?main(String?args[])?throws
??IOException,IndexOutOfBoundsException?{
??……
??}
最后,我們?cè)俅螐?qiáng)調(diào),對(duì)于非運(yùn)行時(shí)例外,如前例中的IOException等,程序中必須要作出處理,或者捕獲,或者聲明拋棄。而對(duì)于運(yùn)行時(shí)例外,如前例中的ArithmeticException,
IndexOutOfBoundsException,則可以不做處理
拋棄異常的例子(對(duì)之前的進(jìn)行改進(jìn))
//?Exception4.java
import?java.io.*;
p?lic?class?Exception4{
?p?lic?static?void?main(String?args[])throws?FileNotFoundException,IOException{
FileInputStream?fis=new?FileInputStream(“text.txt”);
int?b;
while((b=fis.read())!=-1){
??System.out.print(b);
?}
??fis.close();
?}
}
捕獲異常的例子(對(duì)之前的進(jìn)行改進(jìn))
import?java.io.*;
p?lic?class?Exception5{
p?lic?static?void?main(String?args[])?{
?try{
???FileInputStream?fis=new?FileInputStream(“text.txt”);
int?b;
while((b=fis.read())!=-1){
System.out.print(b);
}
??fis.close();
?}catch(FileNotFoundException?e)
??{ ????
???System.out.println(?e?);
??System.out.println(?"message:?"+e.getMessage()?); ??????e.printStackTrace(?System.out?); ????
??}catch(IOException?e)
???{ ????
System.out.println(?e?);
??}?
}?
(3)拋出異常:
拋出異常就是產(chǎn)生異常對(duì)象的過(guò)程,首先要生成異常對(duì)象,異常或者由虛擬機(jī)生成,或者由某些類的實(shí)例生成,也可以在程序中生成。在方法中,拋出異常對(duì)象是通過(guò)throw語(yǔ)句實(shí)現(xiàn)的。
例如:
?IOException?e=new?IOException();
?throw?e?;
可以拋出的異常必須是Throwable或其子類的實(shí)例。下面的語(yǔ)句在編譯時(shí)將會(huì)產(chǎn)生語(yǔ)法錯(cuò)誤:
throw?new?String("throw?anything");
自定義異常類必須是Throwable的直接或間接子類。
顯示拋出異常詳細(xì)情況的例子
//Exception6.java
p?lic?class?Exception6?{?
p?lic?static?void?main(String[]?args)?{??
try?{??
?throw?new?Exception("My?Exception");?????}?catch?(Exception?e)
???{
???System.err.println("Caught?Exception");???
???System.err.println("getMessage():"?+?e.getMessage());??
???System.err.println("getLocalizedMessage():"+?e.getLocalizedMessage());??????????
???System.err.println("toString():"?+?e);?????????
???System.err.println("printStackTrace():");????????????e.printStackTrace();
???}?
}
}?
程序運(yùn)行結(jié)果如下:
d:\user\chap08>java?Exception6
Caught?Exception
getMessage():My?Exception
getLocalizedMessage():My?Exception
toString():java.lang.Exception:?My?Exception
printStackTrace():
java.lang.Exception:?My?Exception
?at?Exception6.main(Exception6.java:5)
try-catch-finally嵌套的例子
class?MyoneException?extends?Exception?{
}
p?lic?class?TryInbed?{
???p?lic?static?void?main(String[]?args)?{
??System.out.println("Entering?first?try?block");
??try?{
?System.out.println("Entering?second?try?block");
?try?{
throw?new?MyoneException();
?}?finally?{
System.out.println("finally?in?2nd?try?block");
?}//try-catch-finally嵌套在try限定的范圍內(nèi)。
??}?catch?(MyoneException?e)?{
?System.err.println("Caught?MyoneException?in?1st?try?block");
??}?finally?{
?System.err.println("finally?in?1st?try?block");
??}
???}
}
程序運(yùn)行結(jié)果如下:
Entering?first?try?block
Entering?second?try?block
finally?in?2nd?try?block
Caught?MyoneException?in?1st?try?block
finally?in?1st?try?block
(4)創(chuàng)建用戶異常類:
如果?Java?提供的系統(tǒng)異常類型不能滿足程序設(shè)計(jì)的需求,我們可以設(shè)計(jì)自己的異常類型。
從?Java?異常類的結(jié)構(gòu)層次可以看出,Java?異常的公共父類為?Throwable?。在程序運(yùn)行中可能出現(xiàn)兩種問(wèn)題:一種是由硬件系統(tǒng)或JVM導(dǎo)致的故障,?Java?定義該故障為?Error?。這類問(wèn)題用戶程序不
能夠處理的。另外一種問(wèn)題是程序運(yùn)行錯(cuò)誤,Java?定義為?Exception。這種情況下,可以通過(guò)程序設(shè)計(jì)的調(diào)整來(lái)實(shí)現(xiàn)異常處理。
因此,用戶定義的異常類型必須是?Throwable?的直接或間接子類。Java?推薦用戶的異常類型以?Exception?為直接父類。創(chuàng)建用戶異常的方法如下:
?class?UserException?extends?Exception{
??UserException(){
?super();
??……?//其它語(yǔ)句
??}??
?}
我們?cè)谑褂卯惓r(shí),有以下幾點(diǎn)建議需要注意:
(1)?對(duì)于運(yùn)行時(shí)例外,如果不能預(yù)測(cè)它何時(shí)發(fā)生,程序可以不做處理,而是讓Java虛機(jī)去處理它。
(2)?如果程序可以預(yù)知運(yùn)行時(shí)例外可能發(fā)生的地點(diǎn)和時(shí)間,則應(yīng)該在程序中進(jìn)行處理,而不應(yīng)簡(jiǎn)單地把它交給運(yùn)行時(shí)系統(tǒng)。(3)在自定義異常類時(shí),如果它所對(duì)應(yīng)的異常事件通常總是在運(yùn)行時(shí)產(chǎn)生的,而
且不容易預(yù)測(cè)它將在何時(shí)、何處發(fā)生,則可以把它定義為運(yùn)行時(shí)例外,否則應(yīng)定義為非運(yùn)行時(shí)例外。
用戶定義的異常類的使用
//?Exceptionjava
class?MyotherException?extends?Exception?{??//用戶定義的異常
???p?lic?MyotherException()?{??
???}
???p?lic?MyotherException(String?msg)?{
??super(msg);
???}
}
p?lic?class?Exception8?{
???p?lic?static?void?f()?throws?MyotherException?{
??System.out.println("Throwing?MyotherException?from?f()");
??throw?new?MyotherException();
???}
???p?lic?static?void?g()?throws?MyotherException?{
??System.out.println("Throwing?MyotherException?from?g()");
??throw?new?MyotherException("Originated?in?g()");
???}
???p?lic?static?void?main(String[]?args)?{
??try?{?
???f();
??}catch?(MyotherException?e)?{
e.printStackTrace();
??}
??try?{??
???g();
??}?catch?(MyotherException?e)?{
e.printStackTrace();
??}
?}
}
程序的運(yùn)行結(jié)果如下:
Throwing?MyotherException?from?f()
Throwing?MyotherException?from?g()
MyotherException
at?Exceptionf(Exceptionjava:13)
at?Exceptionmain(Exceptionjava:21)
MyotherException:?Originated?in?g()
at?Exceptiong(Exceptionjava:17)
at?Exceptionmain(Exceptionjava:26)
?
轉(zhuǎn)載于:https://blog.51cto.com/7825719/1283781
總結(jié)
以上是生活随笔為你收集整理的黑马程序员_java异常处理机制的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: modelsim-altera
- 下一篇: 检测某个IP是否属于某个网段范围