Java異常類型
所有異常類型都是Throwable的子類,Throwable把異常分成兩個(gè)不同分支的子類Error和Exception。

Error類型的異常表示運(yùn)行應(yīng)用程序中較嚴(yán)重問題。大多數(shù)錯(cuò)誤表示代碼運(yùn)行時(shí) JVM(Java 虛擬機(jī))出現(xiàn)的問題。
Exception類型是程序本身可以處理的異常,它又分為非運(yùn)行時(shí)異常和運(yùn)行時(shí)異常(RuntimeException即運(yùn)行期問題)。非運(yùn)行時(shí)異常需要手動(dòng)添加捕獲及處理語句,如果不處理,編譯則不通過;運(yùn)行時(shí)異常是jvm正常運(yùn)行期間拋出的錯(cuò)誤,這些異常是不檢查異常(編譯器不會(huì)去檢查它),一般由程序邏輯錯(cuò)誤所引起,是代碼本身有問題,這種問題我們不處理。
如果程序出了問題,并且我們沒有做任何處理,最終會(huì)被默認(rèn)處理程序處理,默認(rèn)處理程序會(huì)把異常的信息打印在控制臺,同時(shí)程序停止運(yùn)行。
對于所有的可查異常,java規(guī)定:方法必須捕捉,如果不捕捉,則必須聲明拋出異常
java內(nèi)置異常類
非檢查性異常
ArithmeticException:算數(shù)錯(cuò)誤。如,一個(gè)整數(shù)"除以零"
ArrayIndexOutOfBoundsException:數(shù)組下標(biāo)出界。
ArrayStoreException:數(shù)組元素賦值類型不兼容
ClassCastException:非法強(qiáng)制轉(zhuǎn)換類型
IllegalArgumentException:向方法傳遞了一個(gè)不合法或不正確的參數(shù)
IllegalMonitorStateException:非法監(jiān)控操作,如等待一個(gè)未鎖定線程
IllegalStateException:環(huán)境應(yīng)用狀態(tài)不正確
IllegalThreadStateException:請求操作與當(dāng)前線程狀態(tài)不兼容
IndexOutOfBoundsException:某些類型索引超出范圍
NegativeArraySizeException:應(yīng)用程序試圖創(chuàng)建大小為負(fù)的數(shù)組
NullPointerException:當(dāng)應(yīng)用程序試圖在需要對象的地方使用 null 時(shí),拋出該異常
NumberFormatException:字符串到數(shù)字格式的非法轉(zhuǎn)換
SecurityException:由安全管理器拋出的異常,指示存在安全侵犯
StringIndexOutOfBoundsException:索引為負(fù),或者超出字符串的大小
UnsupportedOperationException:遇到不支持請求的操作
檢查行異常
ClassNotFoundException:找不到相應(yīng)的類CloneNotSupportedException:試圖克隆一個(gè)無法實(shí)現(xiàn) Cloneable 接口的對象
IllegalAccessException:對一個(gè)類的訪問被拒絕
InstantiationException:試圖創(chuàng)建一個(gè)抽象接口或抽象類的對象
InterruptedException:一個(gè)線程被另一個(gè)線程中斷
NoSuchFieldException:請求的變量不存在
NoSuchMethodException:請求的方法不存在
try...catch
try/catch關(guān)鍵字可以捕獲異常
try{
可能出現(xiàn)問題的代碼
}catch(異常名 變量){
針對問題的處理
}
一旦異常被引發(fā),程序控制轉(zhuǎn)到catch塊,執(zhí)行了catch語句后,程序控制從整個(gè)try/catch機(jī)制的下面一行繼續(xù)。一個(gè)catch語句不能捕獲另一個(gè)try聲明所引發(fā)的異常(除非是嵌套的try語句情況)。不能單獨(dú)使用try。構(gòu)造catch語句的目的是不中斷程序的運(yùn)行。
try里面定義的屬性只能在try塊中使用
class Demo{
public static void main(String[] args){
int a,b;
try{
a=5;
b=0;
System.out.println(a/b);
}catch(ArithmeticException e){
System.out.println("Division by zero");
}
System.out.println("After catch exception");
}
}
結(jié)果為:Division by zero
After catch exception
某些情況下單個(gè)代碼可能引起多個(gè)異常,處理這種情況可以定義更多的catch子句,每個(gè)子句捕獲一種類型的異常。
當(dāng)異常被引發(fā),每一個(gè)catch子句被依次檢查,匹配上異常類型的子句執(zhí)行,然后代碼從try/catch塊后面開始繼續(xù)。
注意:異常子類必須在它們父類前面(如果不這樣,編譯器會(huì)報(bào)錯(cuò)),這是因?yàn)檫\(yùn)用父類的catch語句將捕獲該類型及其所有子類類型的異常。
class Demo{
public static void main(String[] args){
int[] a={1,2};
try{
a[34]=5;
}catch(ArrayIndexOutOfBoundsException e){
? ? ?System.out.println("ArrayIndexOutOfBoundsException catch");
}catch(Exception e){
? ? ?System.out.println("Exception catch");
}
System.out.println("After catch exception");
}
}
結(jié)果為:ArrayIndexOutOfBoundsException catch
After catch exception
try語句可以被嵌套,也就是說一個(gè)try語句可以在另一個(gè)try語句內(nèi)部。
建議最好不要嵌套
public class Demo {
?public static void main(String[] args) {
? ?try{
? ? ?int a=args.length;
? ? ?int b=42/a;
? ? ?System.out.println("a="+a);
? ? try{
? ? ? ?if(a==1)
? ? ? ?a=a/(a-a);
? ? ? ?if(a==2){
? ? ? ? ?int c[]={1};
? ? ? ? ?c[43]=9;
? ? ? ?}
? ? ?}catch(ArrayIndexOutOfBoundsException e){
? ? ? ?System.out.println("ArrayIndexOutOfBounds:"+e);
? ? ?}
? ?}catch(ArithmeticException e){
? ? ?System.out.println("Divide by:"+e);
? ?}
?}
}
結(jié)果:Divide by:java.lang.ArithmeticException: / by zero
如果a=1,則結(jié)果為:a=1Divide by:java.lang.ArithmeticException: / by zero如果a=2,則結(jié)果為:a=2ArrayIndexOutOfBounds:java.lang.ArrayIndexOutOfBoundsException: 43粗體的try語句嵌套在了外面這個(gè)大的try塊中,內(nèi)部的try塊不含有處理這個(gè)異常的catch語句,它將把異常傳給外面的try塊,在那里異常被檢查是否與之匹配,這個(gè)過程將繼續(xù)直到匹配成功。如果沒有catch語句與之匹配,java運(yùn)行時(shí)系統(tǒng)將自動(dòng)處理這個(gè)異常。
finally
finally塊無論有沒有異常拋出都會(huì)執(zhí)行,所以finally一般用來關(guān)閉資源。每個(gè)try語句至少,需要一個(gè)catch或finally字句。finally塊可有可無,不作強(qiáng)制要求。
當(dāng)在try塊或catch塊中遇到return語句時(shí),finally語句塊將在方法返回之前被執(zhí)行。如果finally語句塊中也有return語句,那么直接從finally中返回了,而且finally中的return會(huì)使拋出的異常丟失,所以不建議在finally中ruturn.。finally中拋出的異常會(huì)覆蓋catch中拋出的異常。
在以下4種特殊情況下,finally塊不會(huì)被執(zhí)行:
1)在finally語句塊中發(fā)生了異常。
2)在前面的代碼中用了System.exit()退出程序。
3)程序所在的線程死亡。
4)關(guān)閉CPU。
public class Demo {
public static void main(String[] args) {
int[] a={1,2};
try{
a[34]=5;
}catch(ArrayIndexOutOfBoundsException e){
System.out.println("Exception catch");
}finally{
System.out.println("finally");
}
}
}
結(jié)果為:Exception catch
finally
throw
有時(shí)候有些錯(cuò)誤在jvm看來不是錯(cuò)誤,系統(tǒng)就不會(huì)拋出異常(如輸入的年齡小于0),這時(shí)候我們需要手動(dòng)引發(fā)異常。程序可以用throw語句拋出一個(gè)明確的異常。程序在throw語句之后立即停止,后面的任何語句不被執(zhí)行,然后在包含它的所有try塊中(可能在上層調(diào)用函數(shù)中)從里向外尋找含有與其匹配的catch子句的try塊
異常是異常類的實(shí)例對象,我們可以創(chuàng)建異常類的實(shí)例對象通過throw語句拋出
用法:throw 異常對象;
有兩種獲得異常對象的方法:在catch子句中捕獲到的異常對象或者用new操作符創(chuàng)建
public class Demo {static void demo(){try{
throw new ArithmeticException("demo");//新實(shí)例化的異常對象
}catch(ArithmeticException e){
System.out.println("Caught inside demo");
throw e; //捕獲到的異常對象e
}
}
public static void main(String[] args) {
try{
demo();
?}catch(ArithmeticException e){
System.out.println("Caught"+e);
}
}
}結(jié)果為:Caught inside demoCaughtjava.lang.ArithmeticException:demo注意:throw new ArithmeticException();中new用來構(gòu)造ArithmeticException實(shí)例。所有java內(nèi)置的運(yùn)行異常有兩個(gè)構(gòu)造方法:一個(gè)沒有參數(shù),一個(gè)帶有一個(gè)字符串參數(shù)。當(dāng)用第二種形式時(shí),參數(shù)描述指定異常的字符串(拋出異常的原因),如果對象用作print()或println()輸出時(shí),該字符串被顯示(打印異常原因)。
throw是語句拋出異常。它不可以單獨(dú)使用,要么與try…catch配套使用,要么與throws配套使用。
throws
throws 是方法拋出異常,在一個(gè)方法中可能出現(xiàn)了某些異常,我們沒法去處理它,然后就將這個(gè)異常向上拋出。如果一個(gè)方法中沒有捕獲某個(gè)檢查性異常的語句,則該方法必須使用 throws 關(guān)鍵字來聲明,異常的處理則交由它的調(diào)用者。throws 關(guān)鍵字放在方法聲明的尾部。例如汽車出現(xiàn)了故障時(shí),汽車不會(huì)自己去處理這個(gè)異常,而是交給開車的人來處理。
如果一個(gè)方法聲明了throws,然后方法里面有try...catch塊,直接catch異常的引用不再throws(即上層調(diào)用者不會(huì)去處理這個(gè)異常)。
Throws拋出異常的規(guī)則:
1) 如果是不可查異常(unchecked exception),即Error、RuntimeException或它們的子類,那么可以不使用throws關(guān)鍵字來聲明要拋出的異常,編譯仍能順利通過,但在運(yùn)行時(shí)會(huì)被系統(tǒng)拋出。
2)必須聲明方法可拋出的任何可查異常(checked exception)。即如果一個(gè)方法可能出現(xiàn)可查異常,要么用try-catch語句捕獲,要么用throws子句聲明將它拋出,否則會(huì)導(dǎo)致編譯錯(cuò)誤
3)當(dāng)拋出了異常,該方法的調(diào)用者才必須處理或者重新拋出該異常。當(dāng)方法的調(diào)用者無力處理該異常的時(shí)候,應(yīng)該繼續(xù)拋出。
4)調(diào)用方法必須遵循任何可查異常的處理和聲明規(guī)則。若覆蓋一個(gè)方法,則不能聲明與覆蓋方法不同的異常。聲明的任何異常必須是被覆蓋方法所聲明異常的同類或子類。
一個(gè)方法可以聲明拋出多個(gè)異常,多個(gè)異常之間用逗號隔開。
public class Demo {
public static void test() throws ArithmeticException {
? ?throw new ArithmeticException();
}
public static void main(String[] args) {
try{
test();
}catch(ArithmeticException e){
System.out.println("Caught:"+e);
}
}
}
結(jié)果為:Caught:java.lang.ArithmeticException: / by zero
在test()后面聲明throws來引發(fā)ArithmeticException異常,在main方法中必須定義一個(gè)try/catch語句來捕獲該異常
通過throw拋出異常后,如果想在上一級代碼中捕獲并處理異常,需要在拋出異常方法中使用throws關(guān)鍵字在方法聲明中指明要跑出的異常。如果要捕獲throw拋出的異常,必須使用try/catch語句
自定義異常
系統(tǒng)中有些錯(cuò)誤是符合Java語法的,但不符合邏輯,此時(shí)就可以自定義異常。如果異常中沒有我們想要的異常,也剋有自定義一個(gè)異常。比如人的性別是中性時(shí)需要拋出異常,但是一直異常中沒有這個(gè)異常,這時(shí)候我們可以自定義一個(gè)異常拋出。
在 Java 中可以自定義異常。所有異常都必須是 Throwable 的子類。如果希望寫一個(gè)檢查性異常類,則需要繼承 Exception 類。如果你想寫一個(gè)運(yùn)行時(shí)異常類,那么需要繼承 RuntimeException 類。
一般情況下我們都會(huì)直接繼承Exception類
Exception類沒有定義任何方法,它繼承了Throwable提供的一些方法。
Throwable 類的主要方法:
String getMessage():返回關(guān)于發(fā)生的異常的詳細(xì)信息Throwable getCause():返回一個(gè)Throwable 對象代表異常原因
String toString():使用getMessage()的結(jié)果返回類的串級名字
void printStackTrace():打印toString()結(jié)果和棧層次到System.err,即錯(cuò)誤輸出流。
StackTraceElement [] getStackTrace():返回一個(gè)包含堆棧層次的數(shù)組。下標(biāo)為0的元素代表?xiàng)m敚詈笠粋€(gè)元素代表方法調(diào)用堆棧的棧底。
Throwable fillInStackTrace():用當(dāng)前的調(diào)用棧層次填充Throwable 對象棧層次,添加到棧層次任何先前信息中。
Java自定義異常的使用要經(jīng)歷如下四個(gè)步驟:
1、定義一個(gè)類繼承Throwable或其子類。
2、添加構(gòu)造方法(當(dāng)然也可以不用添加,使用默認(rèn)構(gòu)造方法)。
3、在某個(gè)方法類拋出該異常。
4、捕捉該異常。
public class MyException extends Exception { //自定義的MyException異常
}
public class Demo {
static void compute(int a) throws MyException{
System.out.println("Called compute("+a+")");
if(a>10)
throw new MyException();
System.out.println("Normal exit");
}
public static void main(String[] args) {
try{
compute(1);
compute(20);
}catch(MyException e){
System.out.println("Caught:"+e);
}
}
}
結(jié)果為:Called compute(1)
Normal exit
Called compute(20)
Caught:com.DE.MyException