異常處理

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=1
Divide by:java.lang.ArithmeticException: / by zero
如果a=2,則結(jié)果為:a=2
ArrayIndexOutOfBounds: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 demo
Caughtjava.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



最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容