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