標籤:名稱 工具 異常 封裝 自訂異常 覆蓋 通過 stack 問題處理
Java代碼在運行時期發生的問題就是異常。在Java中,把異常資訊封裝成了一個類。當出現了問題時,就會建立異常類對象並拋出異常相關的資訊(如異常出現的位置、原因等)。
註:
1、不要用throws,用try..catch..語句
2、try..catch..語句,try範圍內異常代碼下面的代碼將不會執行,但try..catch..語句下面的代碼將繼續執行
3、RuntimeException異常及其子類不用處理,方法定義中無需throws聲明,運行時期異常一旦發生,需要程式人員修改原始碼。
一、 異常的繼承體系
在Java中使用Exception類來描述異常。
Throwable是Java 語言中所有錯誤或異常的超類,即祖宗類。
與異常Exception平級的有一個Error,它是Throwable的子類,它用來表示java程式中可能會產生的嚴重錯誤。解決辦法只有一個,修改代碼避免Error錯誤的產生。
總結:
1 錯誤:2 (1)錯誤Error:程式員沒辦法處理,只能修改代碼3 (2)異常Exception:可以處理;其中的RuntimeException不用處理
二、異常與錯誤的區別
異常:指程式在編譯、運行期間發生了某種異常(XxxException),我們可以對異常進行具體的處理。若不處理異常,程式將會結束運行。
例:
public static void main(String[] args) { int[] arr = new int[2]; System.out.println(arr[0]); System.out.println(arr[3]);// 該句運行時發生了數組索引越界異常ArrayIndexOutOfBoundsException,由於沒有處理異常,導致程式無法繼續執行,程式結束。 System.out.println("over"); // 由於上面代碼發生了異常,此句代碼不會執行}
錯誤:指程式在運行期間發生了某種錯誤(XxxError),Error錯誤通常沒有具體的處理方式,程式將會結束運行。Error錯誤的發生往往都是系統層級的問題,都是jvm(java虛擬機器)所在系統發生的,並反饋給jvm的。我們無法針對處理,只能修正代碼。
例:
public static void main(String[] args) {int[] arr = new int[1024*1024*100];//該句運行時發生了記憶體溢出錯誤OutOfMemoryError,開闢了過大的數組空間,導致JVM在分配數組空間時超出了JVM記憶體空間,直接發生錯誤。}
三、異常的產生過程解析
先運行下面的程式,程式會產生一個數組索引越界異常ArrayIndexOfBoundsException。我們通過圖解來解析下異常產生的過程。
工具類:
class ArrayTools{//對給定的數組通過給定的角標擷取元素。public static int getElement(int[] arr,int index) { int element = arr[index]; return element;}}
測試類別:
class ExceptionDemo2 { public static void main(String[] args) { int[] arr = {34,12,67}; int num = ArrayTools.getElement(arr,4) System.out.println("num="+num); System.out.println("over"); }}
上述程式執行過程圖解:
四、 拋出異常throw及聲明異常throws
在java中,提供了一個throw關鍵字,它用來拋出一個指定的異常對象。那麼,拋出一個異常具體如何操作呢?
1,建立一個異常對象。封裝一些提示資訊(資訊可以自己編寫)。
2,需要將這個異常對象告知給調用者。怎麼告知呢?怎麼將這個異常對象傳遞到調用者處呢?通過關鍵字throw就可以完成。throw 異常對象;throw用在方法內,用來拋出一個異常對象,將這個異常對象傳遞到調用者處,並結束當前方法的執行。
使用格式:
throw new 異常類名(參數);
例如:
throw new NullPointerException("要訪問的arr數組不存在");throw new ArrayIndexOutOfBoundsException("該索引在數組中不存在,已超出範圍");
下面是異常類ArrayIndexOutOfBoundsException與NullPointerException的構造方法
聲明:將問題標識出來,報告給調用者。如果方法內通過throw拋出了編譯時間異常,而沒有捕獲處理(稍後講解該方式),那麼必須通過throws進行聲明,讓調用者去處理。
聲明異常格式:
修飾符 傳回值類型 方法名(參數) throws 異常類名1,異常類名2… { }
五、捕獲異常try…catch…finally
捕獲異常格式:
try{ 可能會發生的異常的代碼 }catch(異常對象 ex){ 處理語句 }finally{ 不管出不出現異常必須執行語句 一般寫釋放資源的語句 }
例如:
public static void main(String[] args){ int[] arr=null; //try中一旦發生異常,try範圍內的下面代碼將不會執行 try{ int index=get(arr); System.out.println(index); }catch(NullPointerException ex){ System.out.println(ex); }catch(ArrayIndexOutOfBoundsException ex){ System.out.println(ex); }finally{ System.out.println("這是一定會被執行的語句"); } } public static int get(int[] arr) throws NullPointerException,ArrayIndexOutOfBoundsException{ if(arr==null){ throw new NullPointerException("數組為空白"); } if(arr.length<4){ throw new ArrayIndexOutOfBoundsException("數組長度不夠"); } return arr[3]+1; }}
六、try…catch…finally異常處理的組合方式
(1)try catch finally組合:檢測異常,並傳遞給catch處理,並在finally中進行資源釋放。
(2)try catch組合 : 對代碼進行異常檢測,並對檢測的異常傳遞給catch處理。對異常進行捕獲處理。
(3)一個try 多個catch組合 : 對代碼進行異常檢測,並對檢測的異常傳遞給catch處理。對每種異常資訊進行不同的捕獲處理。
注意:這種異常處理方式,要求多個catch中的異常不能相同,並且若catch中的多個異常之間有子父類異常的關係,那麼子類異常要求在上面的catch處理,父類異常在下面的catch處理。
(4)try finally 組合: 對代碼進行異常檢測,檢測到異常後因為沒有catch,所以一樣會被預設jvm拋出。異常是沒有捕獲處理的。但是功能所開啟資源需要進行關閉,所有finally。只為關閉資源。
七、 運行時期異常
RuntimeException和他的所有子類異常,都屬於運行時期異常。NullPointerException,ArrayIndexOutOfBoundsException等都屬於運行時期異常.
運行時期異常的特點:
1、 方法中拋出運行時期異常,方法定義中無需throws聲明,調用者也無需處理此異常
2、 運行時期異常一旦發生,需要程式人員修改原始碼.
八、異常在方法重寫中細節
1、 子類覆蓋父類方法時,如果父類的方法聲明異常,子類只能聲明父類異常或者該異常的子類,或者不聲明。
例如:class Fu { public void method () throws RuntimeException {}}class Zi extends Fu { public void method() throws RuntimeException { } //拋出父類一樣的異常 //public void method() throws NullPointerException{ } //拋出父類子異常}
2、當父類方法聲明多個異常時,子類覆蓋時只能聲明多個異常的子集。
例如:class Fu { public void method () throws NullPointerException, ClassCastException{}}class Zi extends Fu { public void method()throws NullPointerException, ClassCastException { }
public void method() throws NullPointerException{ } //拋出父類異常中的一部分 public void method() throws ClassCastException { } //拋出父類異常中的一部分}
3、當被覆蓋的方法沒有異常聲明時,子類覆蓋時無法聲明異常的
例如:class Fu { public void method (){}}class Zi extends Fu { public void method() throws Exception { }//錯誤的方式}
舉例:父類中會存在下列這種情況,介面也有這種情況
問題:介面中沒有聲明異常,而實現的子類覆蓋方法時發生了異常,怎麼辦?
答:無法進行throws聲明,只能catch的捕獲。萬一問題處理不了呢?catch中繼續throw拋出,但是只能將異常轉換成RuntimeException子類拋出。
interface Inter { public abstract void method();}class Zi implements Inter { public void method(){ //無法聲明 throws Exception int[] arr = null; if (arr == null) { //只能捕獲處理 try{throw new Exception(“哥們,你定義的數組arr是空的!”);} catch(Exception e){ System.out.println(“父方法中沒有異常拋出,子類中不能拋出Exception異常”); //我們把異常對象e,採用RuntimeException異常方式拋出 throw new RuntimeException(e);}}}}
九、異常中常用方法
在Throwable類中為我們提供了很多操作異常對象的方法:
即:
1、 printStackTrace:在控制台輸出該異常的名稱與詳細資料字串、異常出現的代碼位置
2、toString方法:返回該異常的名稱與詳細資料字串
3、getMessage方法:返回該異常提示資訊
十、自訂異常
1、自訂異常類的定義
格式:
Class 異常名 extends Exception{ //或繼承RuntimeException public 異常名(){ } public 異常名(String s){ super(s); }}
(1)自訂異常繼承Exception示範
class MyException extends Exception{ /*為什麼要定義建構函式,因為看到Java中的異常描述類中有提供對異常對象的初始化方法。*/ public MyException(){ super(); } public MyException(String message) { super(message);// 如果自訂異常需要異常資訊,可以通過調用父類的帶有字串參數的建構函式即可。 }}
(2)自訂異常繼承RuntimeException示範
class MyException extends RuntimeException{ /*為什麼要定義建構函式,因為看到Java中的異常描述類中有提供對異常對象的初始化方法。*/ MyException(){ super(); } MyException(String message) { super(message);// 如果自訂異常需要異常資訊,可以通過調用父類的帶有字串參數的建構函式即可。 }}
總結一下,建構函式到底拋出這個NoAgeException是繼承Exception呢?還是繼承RuntimeException呢?
繼承Exception,必須要throws聲明,一聲明就告知調用者進行捕獲,一旦問題處理了調用者的程式會繼續執行。
繼承RuntimeExcpetion,不需要throws聲明的,這時調用是不需要編寫捕獲代碼的,因為調用根本就不知道有問題。一旦發生NoAgeException,調用者程式會停掉,並有jvm將資訊顯示到螢幕,讓調用者看到問題,修正代碼。
java--異常