Java程式設計基礎 ---- 異常
異常:
就是不正常,程式在執行時出現的不正常情況,例如之前陣列操作所提到的角標越界、空指標等異常。其實就是程式中出現的問題。這個問題按照面向物件思想進行描述,並封裝成了物件。
因為問題的產生有產生的原因、有問題的名稱、有問題的描述等多個屬性資訊存在。當出現多屬性資訊最方便的方式就是將這些資訊進行封裝。異常就是java按照面向物件的思想將問題進行物件封裝。這樣就方便於操作問題以及處理問題。
對這些問題進行分類。而且這些問題都有共性內容比如:每一個問題都有名稱,同時還有問題描述的資訊,問題出現的位置,所以可以不斷的向上抽取。形成了異常體系:
--------java.lang.Throwable:
|----Error:錯誤,一般情況下,不編寫針對性的程式碼進行處理,通常是jvm發生的,需要對程式進行修正。
|----Exception:異常,可以有針對性的處理方式
無論是錯誤還是異常,它們都有具體的子類體現每一個問題,它們的子類都有一個共性,就是都以父類名才作為子類的字尾名。
異常體系的特點:
異常體系中的所有類以及建立的物件都具備可拋性,也就是說可以被throw和throws關鍵字所操作(只有異常體系具備整個特點)。
throw和throws的用法:
throw定義在函式內,用於丟擲異常物件。
throws定義在函式上,用於丟擲異常類,可以丟擲多個,用逗號隔開。
如何標示呢?
通過throws關鍵字完成,格式:throws 異常類名,異常類名…
這樣標示後,呼叫者,在使用該功能時,就必須要處理,否則編譯失敗。
程式碼演示:丟擲異常的方法
當函式內有throw丟擲異常物件,並未進行try處理,則必須要在函式上宣告,否則編譯失敗(RuntimeException除外)。也就是說,函式內如果丟擲RuntimeException異常,函式上可以不用宣告。
需要宣告的原因:是需要呼叫者對該異常進行處理。
如果函式聲明瞭異常,呼叫者需要處理,處理方式可throws可try。
異常分兩種:
1、 編譯時被檢測異常:
該異常在編譯時,如果沒有進行處理(沒有throws也沒有try),則會編譯失敗。
注:只要是Exception及其子類都是編譯時被檢測的異常。
2、執行時異常(編譯時不檢測):
在編譯時,不需要處理,編譯器也不檢查。該異常發生,建議不處理,讓該程式停止,需要對程式碼進行修正。其中Exception有一個特殊的子類RuntimeException,以及RuntimeException的子類是執行異常,也就說這個異常是編譯時不被檢查的異常。
執行時異常如果在函式內被丟擲,在函式上不需要宣告。
不宣告的原因:不需要呼叫者處理,執行時異常發生,已經無法再讓程式繼續執行,所以,不讓呼叫處理的,直接讓程式停止,由呼叫者對程式碼進行修正。
異常處理語句:
try {
需要被檢測的程式碼;
}
catch(異常類 變數名){
異常處理程式碼;
}
fianlly{
一定會執行的程式碼;
}
有三種結合格式:
1、try {}
catch() {}
2、try {}
finally {}
3、try {}
catch() {} finally {}
注:1、finally中定義的通常是關閉資原始碼,應為資源必須釋放;
2、在catch中若有System.exit(0); //系統退出(jvm結束), finally將讀不到。
程式碼演示:
結果為:
獲取異常資訊的方式:通過catch處理
catch(Exception e) { //e用於接收try檢測到的異常物件。
System.out.println(“message:”+e.getMessage());//獲取的是異常的資訊。
System.out.println(“toString:”+e.toString());//獲取的是異常的名字+異常的資訊。
e.printStackTrace();//列印異常在堆疊中資訊;異常名稱+異常資訊+異常的位置。
}
異常處理原則:功能丟擲幾個異常,功能呼叫如果進行try處理,需要與之對應的catch處理程式碼塊,這樣的處理有針對性,拋幾個就處理幾個。
注:try對應多個catch時,如果有父類的catch語句塊,一定要放在下面。
定義異常處理時,什麼時候定義try,什麼時候定義throws呢?
功能內部如果出現異常,如果內部可以處理,就用try;
如果功能內部處理不了,就必須宣告出來,讓呼叫者處理。使用throws丟擲,交給呼叫者處理。誰呼叫了這個功能誰就是呼叫者;
自定義異常:
當開發時,專案中出現了java中沒有定義過的問題時,這時就需要我們按照java異常建立思想,將程式中出現的特有問題進行物件的封裝。這個異常,稱為自定義異常。
對於除法運算,0作為除數是不可以的。java中對這種問題用ArithmeticException類進行描述。對於這個功能,在我們專案中,除數除了不可以為0外,還不可以為負數。可是負數的部分java並沒有針對描述。所以我們就需要自定義這個異常。
自定義異常的步驟:
1、定義一個子類繼承Exception或RuntimeException,讓該類具備可拋性(既可以使用throw和throws去呼叫此類)。
2、讓該類具備操作異常的共性方法。
當要定義自定義異常的資訊時,可以使用父類已經定義好的功能。將異常資訊傳遞給父類的建構函式。
class MyException extends
Exception{
MyException(String Message){
Super(message);
}
}
例如,對除數為0和負數的情況自定義異常:
執行結果:
<>
異常的好處:
1、可以將問題進行封裝;
2、將正常流程程式碼和問題處理程式碼相分離,方便於閱讀。
異常的處理原則:
處理方式有兩種:try或者throws;
呼叫到丟擲異常的功能時,丟擲幾個,就處理幾個(一個try對應多個catch);多個catch,父類的catch放到最下面;
catch內,需要定義針對性的處理方式。不要簡單地定義printStackTrace或者輸出語句,也不要不寫。
異常的轉換思想:當出現的異常是呼叫者處理不了的,就需要將此異常轉換為一個呼叫者可以處理的異常丟擲。
try{
throw new AException();
}
catch(AException e){
throw e;
}
如果異常處理不了,但並不屬於該功能出現的異常。可以將異常轉換後,再丟擲和該功能相關的異常。
或者異常可以處理,但需要將異常產生的和本功能相關的問題提供出去,讓呼叫者知道,並處理。也可以將捕獲異常處理後,轉換新的異常丟擲。
try{
throw new AException();
}
catch(AException e){
//對AException處理
throw new BException();
}
當異常出現後,在子父類進行覆蓋時,有了一些新的特點:
1、當子類覆蓋父類的方法時,如果父類的方法丟擲了異常,那麼子類的方法要麼不丟擲異常要麼丟擲父類異常或者該異常的子類,不能丟擲其他異常。
2、如果父類或者介面中的方法沒有丟擲過異常,那麼子類是不可以丟擲異常的,如果子類的覆蓋的方法中出現了異常,只能try不能throws。
注意:
如果這個異常子類無法處理,已經影響了子類方法的具體運算,這時可以在子類方法中,通過throw丟擲RuntimeException異常或者其子類,這樣,子類的方法上是不需要throws宣告的。
throw單獨存在時,下面不要定義語句,因為執行不到。
常見異常:
1、腳標越界異常(IndexOutOfBoundsException)包括陣列、字串;
2、型別轉換異常:ClassCastException
3、空指標異常:NullPointerException
4、不支援操作異常;
異常要儘量避免,如果避免不了,需要預先給出處理方式。比如家庭備藥,比如滅火器。
本文章是基於張孝祥老師java基礎課程總結,轉載請註明。