異常機制(Exception)
軟件程序在運行過程中,非常可能遇到異常問題。常見的異常:
1、用戶輸入錯誤
2、設備錯誤
3、硬件問題,例如打印機關掉、服務器問題
4、物理限制:磁盤滿了
Java是采用面向對象的方式來處理異常的。
處理過程
拋出異常:在執行一個方法是,如果發生異常,則這個方法生成代表該異常的一個對象,停止當前執行路徑,并把異常對象提交給JRE。
捕獲異常:JRE得到該異常后,尋找相應的代碼來處理該異常。JRE在方法的調用棧中查找,從生成異常的方法開始回溯,直到找到相應的異常處理代碼為止。
JDK中定義了很多異常類,這些類對應了各種各樣可能出現的異常時間,所有異常對象都是派生于Throwable類的一個實例。如果內置的異常類不能夠滿足需要,還可以創建自己的異常類。Error 錯誤類,不需要程序員管,是一個錯誤,關鍵在于Exception,需要我們程序員管。
Error
Error類層次描述了Java運行時系統內部錯誤和資源耗盡錯誤。這類錯誤是我們無法控制的,同時也是非常罕見的錯誤。所以在編程中,不去處理這類錯誤。Error表明系統JVM已經處于不可恢復的崩潰狀態中。
Exception
所有異常類的父類,其子類對應了各種各樣可能出現的異常事件。
一類特殊的異常,如被0除、數組下標超范圍等,其產生比較頻繁,處理麻煩,如果顯式的聲明或捕獲將會對程序可讀性和運行效率影響很大。因此由系統自動檢測并將它們交給缺省的異常處理程序(用戶可不必對其處理)
NullpointException
(空指針異常,遇到的最多的異常)
Checked Exception
這一類異常,我們必須捕獲進行處理
異常的處理方法1(親自動手捕獲):
Try:try語句指定了一段代碼,該段代碼就是一次捕獲并處理的范圍。在執行過程中,當任意一條語句產生異常時,就會跳過該段中后面的代碼。代碼中可能會產生并拋出一種或幾種類型的異常對象,它后面的catch語句要分別對這些異常做相應的處理
一個try語句必須帶有至少一個catch語句塊或一個finally語句塊。注意當異常處理的代碼執行結束以后,是不會回到try語句去執行尚未執行的代碼。
Catch:每個try語句塊可以伴隨一個或多個catch語句,用于處理可能產生的不同類型的異常對象。Catch捕獲異常時的捕獲順序:如果異常類之間由繼承關系,在順序安排上需注意。越是頂層的類,越放在下面。再不然就直接把多余的catch省略掉。
finally關鍵字
有些語句,不管是否發生了異常,都必須要執行,那么就可以把這樣的語句放到finally語句塊中。通常在finally中關閉程序塊已打開的資源,比如:文件流、釋放數據庫連接等。
使用格式:
try{可能出現異常的代碼}catch(異常 對象名){處理異常的代碼-> 將來開發會將異常信息保存到日志文件中}finally{不管是否有異常,都會執行的代碼}
try-catch-finally-return執行順序
-
try中帶有return
當try中帶有return時,會先執行return前的代碼,然后暫時保存需要return的信息,再執行finally中的代碼,最后再通過return返回之前保存的信息。但如果finally通過地址改變了變量,還是會影響方法返回值的。 -
catch中帶有return
catch中return與try中一樣,會先執行return前的代碼,然后暫時保存需要return的信息,再執行finally中的代碼,最后再通過return返回之前保存的信息。 -
finally中帶有return
當finally中有return的時候,try中的return會失效,在執行完finally的return之后,就不會再執行try中的return。這種寫法,編譯是可以編譯通過的,但是編譯器會給予警告,所以不推薦在finally中寫return,這會破壞程序的完整性,而且一旦finally里出現異常,會導致catch中的異常被覆蓋。
總結:
- finally中的代碼總會被執行。
- 當try、catch中有return時,也會執行finally。return的時候,要注意返回值的類型,是否受到finally中代碼的影響。
- finally中有return時,會直接在finally中退出,導致try、catch中的return失效。
異常的處理方法2(聲明異常:throws子句)
當Checked Exception產生時,不一定立刻處理它,可以再把異常Throws出去。如果一個方法拋出多個已檢查異常,就必須在方法的首部列出所有的異常,之間以逗號隔開。
方法重寫中聲明異常原則:子類聲明的異常范圍不能超過父類聲明的范圍。即1、父類沒有聲明異常,子類也不能;2、不可拋出原有方法拋出異常類的父類或上層類
自定義異常
在程序中,可能會遇到任何標準異常類都沒有充分的描述清楚的問題,這種情況下可以創建自己的異常類,從Exception類或者它的子類派生一個子類即可。習慣上,定義的類應該包含2個構造器:一個是默認的構造器,另一個是帶有詳細信息的構造器。
- 定義一個類
- 如果繼承Exception 就是編譯時期異常
- 如果繼承RuntimeException,就是運行時期異常
使用異常機制建議
- 要避免使用異常處理代替錯誤處理,這樣會降低程序的清晰性,并且效率低下。
- 處理異常不可以代替簡單測試(只在異常情況下使用異常機制)
- 不要進行小粒度的異常處理——應該將整個任務包裝在一個Try語句塊中
- 異常往往在高層處理
打印異常信息的三個方法
這些方法均繼承于Throwable類:
- String toString() :輸出異常類型和設置的異常信息
- String getMessage(): 輸出設置的異常信息 ,只顯示產生異常的原因,但不顯示類名。
- void printStackTrace():打印異常信息是最全的:包括異常類型,信息,以及出現的行數等,常用來跟蹤異常事件發生時堆棧的內容。
public class Exception {public static void main(String[] args) {//1.定義一個用戶名,代表已經注冊的用戶String username = "root";//2.創建Scanner對象,錄入用戶名Scanner sc = new Scanner(System.in);System.out.println("請您輸入要登錄的用戶名:");String name = sc.next();//3.判斷用戶名是否和已經存在的用戶名一致if (name.equals(username)) {System.out.println("登錄成功了");} else {try {throw new LoginUserException("登錄失敗了,用戶名或者密碼有問題");}catch (Exception e){System.out.println(e.toString()); //輸出異常類型和設置的異常信息System.out.println(e.getMessage()); //輸出設置的異常信息 ,只顯示產生異常的原因,但不顯示類名。e.printStackTrace(); //打印異常類型,信息,以及出現的行數}}}
}