異常

異常java

image

查看API中Exception的描述,Exception 類及其子類是 Throwable 的一種形式,它用來表示java程序中可能會產生的異常,並要求對產生的異常進行合理的異常處理數組

繼續觀察,咱們能夠發現Exception有繼承關係,它的父類是Throwable。Throwable是Java 語言中全部錯誤或異常的超類,即祖宗類jvm

image

另外,在異常Exception類中,有一個子類要特殊說明一下,RuntimeException子類,RuntimeException及其它的子類只能在Java程序運行過程當中出現ide

image

咱們再來觀察Throwable類,可以發現與異常Exception平級的有一個Error,它是Throwable的子類,它用來表示java程序中可能會產生的嚴重錯誤。解決辦法只有一個,修改代碼避免Error錯誤的產生函數

image

異常繼承體系總結:工具

Throwable: 它是全部錯誤與異常的超類(祖宗類) |- Error 錯誤 |- Exception 編譯期異常,進行編譯JAVA程序時出現的問題 |- RuntimeException 運行期異常, JAVA程序運行過程當中出現的問題 

異常與錯誤的區別

異常:指程序在編譯、運行期間發生了某種異常(XxxException),咱們能夠對異常進行具體的處理。若不處理異常,程序將會結束運行學習

  • 異常的產生演示以下
public static void main(String[] args) { int[] arr = new int[3]; System.out.println(arr[0]); System.out.println(arr[3]); // 該句運行時發生了數組索引越界異常ArrayIndexOutOfBoundsException,因爲沒有處理異常,致使程序沒法繼續執行,程序結束。 System.out.println("over"); // 因爲上面代碼發生了異常,此句代碼不會執行 } 

錯誤:指程序在運行期間發生了某種錯誤(XxxError),Error錯誤一般沒有具體的處理方式,程序將會結束運行。Error錯誤的發生每每都是系統級別的問題,都是jvm所在系統發生的,並反饋給jvm的。咱們沒法針對處理,只能修正代碼測試

  • 錯誤的產生演示以下
public static void main(String[] args) { int[] arr = new int[1024*1024*100]; //該句運行時發生了內存溢出錯誤OutOfMemoryError,開闢了過大的數組空間,致使JVM在分配數組空間時超出了JVM內存空間,直接發生錯誤。 } 

異常的產生過程解析

先運行下面的程序,程序會產生一個數組索引越界異常ArrayIndexOfBoundsException。咱們經過圖解來解析下異常產生的過程ui

  • 工具類
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"); } } 
  • 上述程序執行過程圖解

image


拋出異常throw

在編寫程序時,咱們必需要考慮程序出現問題的狀況。好比,在定義方法時,方法須要接受參數。那麼,當調用方法使用接受到的參數時,首先須要先對參數數據進行合法的判斷,數據若不合法,就應該告訴調用者,傳遞合法的數據進來。這時須要使用拋出異常的方式來告訴調用者this

在java中,提供了一個throw關鍵字,它用來拋出一個指定的異常對象。那麼,拋出一個異常具體如何操做呢

  • 1,建立一個異常對象。封裝一些提示信息(信息能夠本身編寫)

  • 2.須要將這個異常對象告知給調用者。怎麼告知呢?怎麼將這個異常對象傳遞到調用者處呢?經過關鍵字throw就能夠完成。throw 異常對象

throw用在方法內,用來拋出一個異常對象,將這個異常對象傳遞到調用者處,並結束當前方法的執行

使用格式

throw new 異常類名(參數); 

例如

throw new NullPointerException("要訪問的arr數組不存在"); throw new ArrayIndexOutOfBoundsException("該索引在數組中不存在,已超出範圍"); 
  • 下面是異常類ArrayIndexOutOfBoundsException與NullPointerException的構造方法

image


學習完拋出異常的格式後,咱們經過下面程序演示下throw的使用

  • 編寫工具類,提供獲取數組指定索引處的元素值
class ArrayTools{ //經過給定的數組,返回給定的索引對應的元素值。 public static int getElement(int[] arr,int index) { /* 若程序出了異常,JVM它會打包異常對象並拋出。可是它所提供的信息不夠給力。想要更清晰,須要本身拋出異常信息。 下面判斷條件若是知足,當執行完throw拋出異常對象後,方法已經沒法繼續運算。這時就會結束當前方法的執行,並將異常告知給調用者。這時就須要經過異常來解決。 */ if(arr==null){ throw new NullPointerException("arr指向的數組不存在"); } if(index<0 || index>=arr.length){ throw new ArrayIndexOutOfBoundsException("錯誤的角標,"+index+"索引在數組中不存在"); } int element = arr[index]; return element; } } 
  • 測試類
class ExceptionDemo3 { public static void main(String[] args) { int[] arr = {34,12,67}; //建立數組 int num = ArrayTools.getElement(null,2);// 調用方法,獲取數組中指定索引處元素 //int num = ArrayTools.getElement(arr,5);// 調用方法,獲取數組中指定索引處元素 System.out.println("num="+num);//打印獲取到的元素值 } } 

聲明異常throws

聲明:將問題標識出來,報告給調用者。若是方法內經過throw拋出了編譯時異常,而沒有捕獲處理(稍後講解該方式),那麼必須經過throws進行聲明,讓調用者去處理

  • 聲明異常格式
修飾符 返回值類型 方法名(參數) throws 異常類名1,異常類名2… { } 
  • 聲明異常的代碼演示
class Demo{ /* 若是定義功能時有問題發生須要報告給調用者。能夠經過在方法上使用throws關鍵字進行聲明。 */ public void show(int x)throws Exception { if(x>0){ throw new Exception(); } else { System.out.println("show run"); } } } 

throws用於進行異常類的聲明,若該方法可能有多種異常狀況產生,那麼在throws後面能夠寫多個異常類,用逗號隔開

//多個異常的狀況,例如: public static int getElement(int[] arr,int index) throws NullPointerException, ArrayIndexOutOfBoundsException { if(arr==null){ throw new NullPointerException("arr指向的數組不存在"); } if(index<0 || index>=arr.length){ throw new ArrayIndexOutOfBoundsException("錯誤的角標,"+index+"索引在數組中不存在"); } int element = arr[index]; return element; } 

捕獲異常try…catch…finally

捕獲:Java中對異常有針對性的語句進行捕獲,能夠對出現的異常進行指定方式的處理

  • 捕獲異常格式
try { //須要被檢測的語句。 } catch(異常類 變量) { //參數。 //異常的處理語句。 } finally { //必定會被執行的語句。 } 

try:該代碼塊中編寫可能產生異常的代碼

catch:用來進行某種異常的捕獲,實現對捕獲到的異常進行處理

finally:有一些特定的代碼不管異常是否發生,都須要執行。另外,由於異常會引起程序跳轉,致使有些語句執行不到。而finally就是解決這個問題的,在finally代碼塊中存放的代碼都是必定會被執行的

  • 演示以下
class ExceptionDemo{ public static void main(String[] args){ //throws ArrayIndexOutOfBoundsException try { int[] arr = new int[3]; System.out.println( arr[5] );// 會拋出ArrayIndexOutOfBoundsException 當產生異常時,必須有處理方式。要麼捕獲,要麼聲明。 } catch (ArrayIndexOutOfBoundsException e) { //括號中須要定義什麼呢?try中拋出的是什麼異常,在括號中就定義什麼異常類型。 System.out.println("異常發生了"); } finally { arr = null; //把數組指向null,經過垃圾回收器,進行內存垃圾的清除 } System.out.println("程序運行結果"); } } 

try…catch…finally異常處理的組合方式

  • try catch finally組合:檢測異常,並傳遞給catch處理,並在finally中進行資源釋放

  • try catch組合 : 對代碼進行異常檢測,並對檢測的異常傳遞給catch處理。對異常進行捕獲處理

void show(){ //不用throws try{ throw new Exception();//產生異常,直接捕獲處理 }catch(Exception e){ //處理方式 } } 
  • 一個try 多個catch組合 : 對代碼進行異常檢測,並對檢測的異常傳遞給catch處理。對每種異常信息進行不一樣的捕獲處理
void show(){ //不用throws try{ throw new Exception();//產生異常,直接捕獲處理 }catch(XxxException e){ //處理方式 }catch(YyyException e){ //處理方式 }catch(ZzzException e){ //處理方式 } } 

注意:這種異常處理方式,要求多個catch中的異常不能相同,而且若catch中的多個異常之間有子父類異常的關係,那麼子類異常要求在上面的catch處理,父類異常在下面的catch處理

  • try finally 組合: 對代碼進行異常檢測,檢測到異常後由於沒有catch,因此同樣會被默認jvm拋出。異常是沒有捕獲處理的。可是功能所開啓資源須要進行關閉,全部finally。只爲關閉資源
void show(){//須要throws try{ throw new Exception(); }finally { //釋放資源 } } 

運行時期異常

  • RuntimeException和他的全部子類異常,都屬於運行時期異常。NullPointerException,ArrayIndexOutOfBoundsException等都屬於運行時期異常

  • 運行時期異常的特色

    • 方法中拋出運行時期異常,方法定義中無需throws聲明,調用者也無需處理此異常
    • 運行時期異常一旦發生,須要程序人員修改源代碼
    class ExceptionDemo{ public static void main(String[] args){ method(); } public static void method(){ throw new RuntimeException(); } } 

異常在方法重寫中細節

  • 子類覆蓋父類方法時,若是父類的方法聲明異常,子類只能聲明父類異常或者該異常的子類,或者不聲明
class Fu { public void method () throws RuntimeException { } } class Zi extends Fu { public void method() throws RuntimeException { } //拋出父類同樣的異常 //public void method() throws NullPointerException{ } //拋出父類子異常 } 
  • 當父類方法聲明一個、多個異常時。子類重寫時聲明的異常最大是RuntimeException
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 { } //拋出父類異常中的一部分 public void method() throws RuntimeException { } // 拋出最大的運行時異常 } 
  • 當被覆蓋的方法沒有異常聲明時,子類覆蓋時最大聲明RuntimeException
class Fu { public void method (){ } } class Zi extends Fu { public void method() throws RuntimeException { } } 

舉例:父類中會存在下列這種狀況,接口也有這種狀況

問題:接口中沒有聲明異常,而實現的子類覆蓋方法時發生了異常,怎麼辦

答:沒法進行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類中爲咱們提供了不少操做異常對象的方法,經常使用的以下

image

  • getMessage方法:返回該異常的詳細信息字符串,即異常提示信息

  • toString方法:返回該異常的名稱與詳細信息字符串

  • printStackTrace:在控制檯輸出該異常的名稱與詳細信息字符串、異常出現的代碼位置 異常的經常使用方法代碼演示

try { Person p= null; if (p==null) { throw new NullPointerException(「出現空指針異常了,請檢查對象是否爲null」); } } catch (NullPointerException e) { String message = e.getMesage(); System.out.println(message ); String result = e.toString(); System.out.println(result); e.printStackTrace(); } 

自定義異常

在上述代碼中,發現這些異常都是JDK內部定義好的,而且這些異常很差找。書寫時也很不方便,那麼能不能本身定義異常呢

以前的幾個異常都是java經過類進行的描述。並將問題封裝成對象,異常就是將問題封裝成了對象。這些異常很差認,書寫也很不方便,能不能定義一個符合個人程序要求的異常名稱。既然JDK中是使用類在描述異常信息,那麼咱們也能夠模擬Java的這種機制,咱們本身定義異常的信息,異常的名字,讓異常更符合本身程序的閱讀。準確對本身所須要的異常進行類的描述


自定義異常類的定義

經過閱讀異常源代碼:發現java中全部的異常類,都是繼承Throwable,或者繼承Throwable的子類。這樣該異常才能夠被throw拋出

說明這個異常體系具有一個特有的特性:可拋性:便可以被throw關鍵字操做

而且查閱異常子類源碼,發現每一個異常中都調用了父類的構造方法,把異常描述信息傳遞給了父類,讓父類幫咱們進行異常信息的封裝

例如NullPointerException異常類源代碼:

public class NullPointerException extends RuntimeException { public NullPointerException() { super();//調用父類構造方法 } public NullPointerException(String s) { super(s);//調用父類具備異常信息的構造方法 } } 

如今,咱們來定義個本身的異常,即自定義異常

格式:

Class 異常名 extends Exception{ //或繼承RuntimeException public 異常名(){ } public 異常名(String s){ super(s); } } 
  • 自定義異常繼承Exception演示
class MyException extends Exception{ /* 爲何要定義構造函數,由於看到Java中的異常描述類中有提供對異常對象的初始化方法。 */ public MyException(){ super(); } public MyException(String message) { super(message);// 若是自定義異常須要異常信息,能夠經過調用父類的帶有字符串參數的構造函數便可。 } } 
  • 自定義異常繼承RuntimeException演示
class MyException extends RuntimeException{ /* 爲何要定義構造函數,由於看到Java中的異常描述類中有提供對異常對象的初始化方法。 */ MyException(){ super(); } MyException(String message) { super(message);// 若是自定義異常須要異常信息,能夠經過調用父類的帶有字符串參數的構造函數便可。 } } 

自定義異常的練習

定義Person類,包含name與age兩個成員變量

在Person類的有參數構造方法中,進行年齡範圍的判斷,若年齡爲負數或大於200歲,則拋出NoAgeException異常,異常提示信息「年齡數值非法」

要求:在測試類中,調用有參數構造方法,完成Person對象建立,並進行異常的處理

  • 自定義異常類
class NoAgeException extends Exception{ NoAgeException() { super(); } NoAgeException(String message) { super(message); } } 
  • Person類
class Person{ private String name; private int age; Person(String name,int age) throws NoAgeException { //加入邏輯判斷。 if(age<0 || age>200) { throw new NoAgeException(age+",年齡數值非法"); } this.name = name; this.age = age; } //定義Person對象對應的字符串表現形式。覆蓋Object中的toString方法。 public String toString() { return "Person[name="+name+",age="+age+"]"; } } 
  • 測試類
class ExceptionDemo{ public static void main(String[] args) { try { Person p = new Person("xiaoming",20); System.out.println(p); } catch (NoAgeException ex){ System.out.println("年齡異常啦"); } System.out.println("over"); } } 

總結一下,構造函數到底拋出這個NoAgeException是繼承Exception呢?仍是繼承RuntimeException呢

  • 繼承Exception,必需要throws聲明,一聲明就告知調用者進行捕獲,一旦問題處理了調用者的程序會繼續執行

  • 繼承RuntimeExcpetion,不須要throws聲明的,這時調用是不須要編寫捕獲代碼的,由於調用根本就不知道有問題。一旦發生NoAgeException,調用者程序會停掉,並有jvm將信息顯示到屏幕,讓調用者看到問題,修正代碼


總結

知識點總結

  • 異常: 就是程序中出現的不正常的現象(錯誤與異常)

    • 異常的繼承體系:
    Throwable: 它是全部錯誤與異常的超類(祖宗類) |- Error 錯誤,修改java源代碼 |- Exception 編譯期異常, javac.exe進行編譯的時候報錯 |- RuntimeException 運行期異常, java出現運行過程當中出現的問題 
  • 異常處理的兩種方式

    • 1,出現問題,本身解決 try…catch…finally
    try{ 可能出現異常的代碼 } catch(異常類名 對象名){ 異常處理代碼 } finally { 異常操做中必定要執行的代碼 } 
    • 2,出現問題,別人解決 throws
    格式: 修飾符 返回值類型 方法名(參數) throws 異常類名1,異常類名2,...{} public void method() throws Exception{} 

異常的根類是Throwable,其下有兩個子類:Error與Exception,日常所說的異常指Exception

  • 異常分類

    • 嚴重錯誤Error,沒法經過處理的錯誤
    • 編譯時異常Exception,編譯時沒法編譯經過。如日期格式化異常
    • 運行時異常RuntimeException,是Exception的子類,運行時可能會報錯,能夠不處理。如空指針異常
  • 異常基本操做

    • 建立異常對象

    • 拋出異常

    • 處理異常

      • 捕獲處理,將異常獲取,使用try/catch作分支處理
      try{ 須要檢測的異常; } catch(異常對象) { 一般咱們只使用一個方法:printStackTrace打印異常信息 } 
      • 聲明拋出處理,出現異常後不處理,聲明拋出給調用者處理。方法聲明上加throws 異常類名
    • 注意:異常的處理,指處理異常的一種可能性,即有了異常處理的代碼,不必定會產生異常。若是沒有產生異常,則代碼正常執行,若是產生了異常,則中斷當前執行代碼,執行異常處理代碼

  • 異常注意事項

    • 多異常處理
      • 捕獲處理:
        • 1多個異常能夠分別處理
        • 2多個異常一次捕獲屢次處理
        • 3多個異常一次捕獲,採用同一種方式處理
      • 聲明拋出異常
        • 聲明上使用,一次聲明多個異常
    • 運行時異常被拋出能夠不處理。即不捕獲也不聲明拋出
    • 若是父類拋出了多個異常,子類覆蓋父類方法時,只能拋出相同的異常或者是他的子集
    • 父類方法沒有拋出異常,子類覆蓋父類該方法時也不可拋出異常。此時子類產生該異常,只能捕獲處理,不能聲明拋出
    • 當多異常處理時,捕獲處理,前邊的類不能是後邊類的父類
  • 自定義異常

    • 若是Java沒有提供你須要的異常,則能夠自定義異常類
    • 定義方法:編譯時異常繼承Exception,運行時異常繼承RuntimeException
相關文章
相關標籤/搜索