異常處理

Java異常類型

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


Error類型的異常表示運行應用程序中較嚴重問題。大多數錯誤表示代碼運行時 JVM(Java 虛擬機)出現的問題。

Exception類型是程序本身可以處理的異常,它又分為非運行時異常和運行時異常(RuntimeException即運行期問題)。非運行時異常需要手動添加捕獲及處理語句,如果不處理,編譯則不通過;運行時異常是jvm正常運行期間拋出的錯誤,這些異常是不檢查異常(編譯器不會去檢查它),一般由程序邏輯錯誤所引起,是代碼本身有問題,這種問題我們不處理。

如果程序出了問題,并且我們沒有做任何處理,最終會被默認處理程序處理,默認處理程序會把異常的信息打印在控制臺,同時程序停止運行。

對于所有的可查異常,java規定:方法必須捕捉,如果不捕捉,則必須聲明拋出異常

java內置異常類

非檢查性異常


ArithmeticException:算數錯誤。如,一個整數"除以零"

ArrayIndexOutOfBoundsException:數組下標出界。

ArrayStoreException:數組元素賦值類型不兼容

ClassCastException:非法強制轉換類型

IllegalArgumentException:向方法傳遞了一個不合法或不正確的參數

IllegalMonitorStateException:非法監控操作,如等待一個未鎖定線程

IllegalStateException:環境應用狀態不正確

IllegalThreadStateException:請求操作與當前線程狀態不兼容

IndexOutOfBoundsException:某些類型索引超出范圍

NegativeArraySizeException:應用程序試圖創建大小為負的數組

NullPointerException:當應用程序試圖在需要對象的地方使用 null 時,拋出該異常

NumberFormatException:字符串到數字格式的非法轉換

SecurityException:由安全管理器拋出的異常,指示存在安全侵犯

StringIndexOutOfBoundsException:索引為負,或者超出字符串的大小

UnsupportedOperationException:遇到不支持請求的操作

檢查行異常


ClassNotFoundException:找不到相應的類

CloneNotSupportedException:試圖克隆一個無法實現 Cloneable 接口的對象

IllegalAccessException:對一個類的訪問被拒絕

InstantiationException:試圖創建一個抽象接口或抽象類的對象

InterruptedException:一個線程被另一個線程中斷

NoSuchFieldException:請求的變量不存在

NoSuchMethodException:請求的方法不存在


try...catch

try/catch關鍵字可以捕獲異常

try{

可能出現問題的代碼

}catch(異常名 變量){

針對問題的處理

}

一旦異常被引發,程序控制轉到catch塊,執行了catch語句后,程序控制從整個try/catch機制的下面一行繼續。一個catch語句不能捕獲另一個try聲明所引發的異常(除非是嵌套的try語句情況)。不能單獨使用try。構造catch語句的目的是不中斷程序的運行。

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");

}

}

結果為:Division by zero

After catch exception


某些情況下單個代碼可能引起多個異常,處理這種情況可以定義更多的catch子句,每個子句捕獲一種類型的異常。

當異常被引發,每一個catch子句被依次檢查,匹配上異常類型的子句執行,然后代碼從try/catch塊后面開始繼續。

注意:異常子類必須在它們父類前面(如果不這樣,編譯器會報錯),這是因為運用父類的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");

}

}

結果為:ArrayIndexOutOfBoundsException catch

After catch exception

try語句可以被嵌套,也就是說一個try語句可以在另一個try語句內部。

建議最好不要嵌套

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);

? ?}

?}

}

結果:Divide by:java.lang.ArithmeticException: / by zero

如果a=1,則結果為:a=1
Divide by:java.lang.ArithmeticException: / by zero
如果a=2,則結果為:a=2
ArrayIndexOutOfBounds:java.lang.ArrayIndexOutOfBoundsException: 43
粗體的try語句嵌套在了外面這個大的try塊中,內部的try塊不含有處理這個異常的catch語句,它將把異常傳給外面的try塊,在那里異常被檢查是否與之匹配,這個過程將繼續直到匹配成功。如果沒有catch語句與之匹配,java運行時系統將自動處理這個異常。

finally

finally塊無論有沒有異常拋出都會執行,所以finally一般用來關閉資源。每個try語句至少,需要一個catch或finally字句。finally塊可有可無,不作強制要求。

當在try塊或catch塊中遇到return語句時,finally語句塊將在方法返回之前被執行。如果finally語句塊中也有return語句,那么直接從finally中返回了,而且finally中的return會使拋出的異常丟失,所以不建議在finally中ruturn.。finally中拋出的異常會覆蓋catch中拋出的異常。

在以下4種特殊情況下,finally塊不會被執行:

1)在finally語句塊中發生了異常。

2)在前面的代碼中用了System.exit()退出程序。

3)程序所在的線程死亡。

4)關閉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");

}

}

}

結果為:Exception catch

finally

throw

有時候有些錯誤在jvm看來不是錯誤,系統就不會拋出異常(如輸入的年齡小于0),這時候我們需要手動引發異常。程序可以用throw語句拋出一個明確的異常。程序在throw語句之后立即停止,后面的任何語句不被執行,然后在包含它的所有try塊中(可能在上層調用函數中)從里向外尋找含有與其匹配的catch子句的try塊

異常是異常類的實例對象,我們可以創建異常類的實例對象通過throw語句拋出

用法:throw 異常對象;

有兩種獲得異常對象的方法:在catch子句中捕獲到的異常對象或者用new操作符創建

public class Demo {
static void demo(){
try{
throw new ArithmeticException("demo");//新實例化的異常對象
}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);
}
}
}
結果為:Caught inside demo
Caughtjava.lang.ArithmeticException:demo
注意:throw new ArithmeticException();中new用來構造ArithmeticException實例。所有java內置的運行異常有兩個構造方法:一個沒有參數,一個帶有一個字符串參數。當用第二種形式時,參數描述指定異常的字符串(拋出異常的原因),如果對象用作print()或println()輸出時,該字符串被顯示(打印異常原因)。

throw是語句拋出異常。它不可以單獨使用,要么與try…catch配套使用,要么與throws配套使用。

throws

throws 是方法拋出異常,在一個方法中可能出現了某些異常,我們沒法去處理它,然后就將這個異常向上拋出。如果一個方法中沒有捕獲某個檢查性異常的語句,則該方法必須使用 throws 關鍵字來聲明,異常的處理則交由它的調用者。throws 關鍵字放在方法聲明的尾部。例如汽車出現了故障時,汽車不會自己去處理這個異常,而是交給開車的人來處理。

如果一個方法聲明了throws,然后方法里面有try...catch塊,直接catch異常的引用不再throws(即上層調用者不會去處理這個異常)。

Throws拋出異常的規則:

1) 如果是不可查異常(unchecked exception),即Error、RuntimeException或它們的子類,那么可以不使用throws關鍵字來聲明要拋出的異常,編譯仍能順利通過,但在運行時會被系統拋出。

2)必須聲明方法可拋出的任何可查異常(checked exception)。即如果一個方法可能出現可查異常,要么用try-catch語句捕獲,要么用throws子句聲明將它拋出,否則會導致編譯錯誤

3)當拋出了異常,該方法的調用者才必須處理或者重新拋出該異常。當方法的調用者無力處理該異常的時候,應該繼續拋出。

4)調用方法必須遵循任何可查異常的處理和聲明規則。若覆蓋一個方法,則不能聲明與覆蓋方法不同的異常。聲明的任何異常必須是被覆蓋方法所聲明異常的同類或子類。

一個方法可以聲明拋出多個異常,多個異常之間用逗號隔開。

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);

}

}

}

結果為:Caught:java.lang.ArithmeticException: / by zero

在test()后面聲明throws來引發ArithmeticException異常,在main方法中必須定義一個try/catch語句來捕獲該異常

通過throw拋出異常后,如果想在上一級代碼中捕獲并處理異常,需要在拋出異常方法中使用throws關鍵字在方法聲明中指明要跑出的異常。如果要捕獲throw拋出的異常,必須使用try/catch語句

自定義異常

系統中有些錯誤是符合Java語法的,但不符合邏輯,此時就可以自定義異常。如果異常中沒有我們想要的異常,也剋有自定義一個異常。比如人的性別是中性時需要拋出異常,但是一直異常中沒有這個異常,這時候我們可以自定義一個異常拋出。

在 Java 中可以自定義異常。所有異常都必須是 Throwable 的子類。如果希望寫一個檢查性異常類,則需要繼承 Exception 類。如果你想寫一個運行時異常類,那么需要繼承 RuntimeException 類。

一般情況下我們都會直接繼承Exception類

Exception類沒有定義任何方法,它繼承了Throwable提供的一些方法。

Throwable 類的主要方法:


String getMessage():返回關于發生的異常的詳細信息

Throwable getCause():返回一個Throwable 對象代表異常原因

String toString():使用getMessage()的結果返回類的串級名字

void printStackTrace():打印toString()結果和棧層次到System.err,即錯誤輸出流。

StackTraceElement [] getStackTrace():返回一個包含堆棧層次的數組。下標為0的元素代表棧頂,最后一個元素代表方法調用堆棧的棧底。

Throwable fillInStackTrace():用當前的調用棧層次填充Throwable 對象棧層次,添加到棧層次任何先前信息中。

Java自定義異常的使用要經歷如下四個步驟:

1、定義一個類繼承Throwable或其子類。

2、添加構造方法(當然也可以不用添加,使用默認構造方法)。

3、在某個方法類拋出該異常。

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);

}

}

}

結果為:Called compute(1)

Normal exit

Called compute(20)

Caught:com.DE.MyException



最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容