Java學習筆記(十三)面向對象---異常

概述

對異常的理解

程序在運行過程當中出現不正常狀況。是對問題的描述,將問題進行對象的封裝。java

異常的由來

問題也是現實生活中一個具體的事物,也能夠經過Java的類的形式進行描述,並封裝成對象。數據庫

對於問題的劃分

一種是嚴重的問題,一種是非嚴重的問題。數組

  • 對於嚴重的:Java經過Error類進行描述。
    對於Error通常不編寫針對性的代碼對其進行處理。
  • 對於非嚴重的:Java經過Exception類進行描述。
    對於Exception可使用針對性的處理方式進行處理。
    不管Error仍是Exception都具備一些共性內容。
    好比:不正常狀況的信息,引起緣由。jvm

    異常體系

Throwable
        |--Error
        |--Exception
            |--RuntimeException

異常體系的特色:
異常體系中的全部類以及被創建的對象都具有可拋性。ide

異常的處理

代碼語句格式

try {
    須要被檢測的代碼
}
catch(異常類 變量) {
    處理異常的代碼(處理方式)
}
finally {
    必定會執行的語句;
}

對異常的常見操做方法

String getMessage();
String toString();
void printStackTrace();函數

class Demo {
    int div(int x,int y) {
        return x/y;
    }
}
public class ExceptionDemo {
    public static void main(String[] args) {
        Demo d = new Demo();
        try {
            int z = d.div(1,0);
            System.out.println(z);
        }
        catch (Exception e) {  //Exception e = new ArithmeticExceptin();
            System.out.println(e.getMessage()); //  /by zero
            System.out.println(e.toString());   //  異常名稱:異常信息
            e.printStackTrace();                //  異常名稱:異常信息,異常出現的位置
            //(jvm默認的處理異常的機制就是在調用printStackTrace()方法)
        }
        System.out.println("over");
    }
}

運行結果this

/ by zero
java.lang.ArithmeticException: / by zero
java.lang.ArithmeticException: / by zero
    at Demo.div(ExceptionDemo.java:3)
    at ExceptionDemo.main(ExceptionDemo.java:10)
over

異常聲明throws

  • throws關鍵字用來聲明一個方法有可能會出現問題。
  • throws關鍵字能夠將異常拋給調用者,能夠層層向上拋,直到最後由Java虛擬機拋出。
    好比:
class Demo {
    int div(int x,int y) throws Exception {
        return x/y;
    }
}
public class ExceptionDemo1 {
    public static void main(String[] args) throws Exception {
        Demo d = new Demo();
        int y = d.div(1,0);
        System.out.println(y);
        System.out.println("over");
    }
}
  • 若是調用者對被調用方法拋出的異常不加處理會出現編譯錯誤。
class Demo {
    int div(int x,int y) throws Exception {
        return x/y;
    }
}
public class ExceptionDemo2 {
    public static void main(String[] args) {
        Demo d = new Demo();
        int y = d.div(1,0);
        System.out.println(y);
        System.out.println("over");
    }
}

上述代碼編譯會提示:code

Error:(9, 22) java: 未報告的異常錯誤java.lang.Exception; 必須對其進行捕獲或聲明以便拋出

咱們對可能出現的異常加以處理:對象

class Demo {
    int div(int x,int y) throws Exception {
        return x/y;
    }
}
public class ExceptionDemo3 {
    public static void main(String[] args) {
        Demo d = new Demo();
        try {
            int y = d.div(1,0);
            System.out.println(y);
        }
        catch (Exception e) {
            System.out.println(e.toString());
        }
        System.out.println("over");
    }
}

運行結果:繼承

java.lang.ArithmeticException: / by zero
over

對可能出現異常的div方法進行處理以後,程序能夠正常編譯運行。

多異常處理

1.聲明異常時,聲明爲更爲具體的異常,這樣能夠處理得更具體。
2.方法聲明有幾個異常,對應就有幾個catch塊。(不要定義多餘的catch塊)
若是多個catch塊中的異常出現繼承關係,父類異常catch塊放在最下面。

class Demo {
    int div(int x,int y) throws ArithmeticException,ArrayIndexOutOfBoundsException {
        int[] arr = new int[x];
        System.out.println(arr[3]);
        return x/y;
    }
}
public class ExceptionDemo4 {
    public static void main(String[] args) {
        Demo d = new Demo();
        try {
            int y = d.div(2,0);
        }
        catch (ArithmeticException e) {
            System.out.println("被零除了");
        }
        catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("數組角標越界");
        }
    }
}

運行結果:

數組角標越界

上述代碼中顯然有兩個一場出現,可是當方法中出現一個異常以後方法會中止運行,不會繼續執行下去。

自定義異常

項目中會出現特有的問題,而這些問題並未被Java描述並封裝對象。因此對這些特有的問題能夠按照Java的對問題封裝的思想,將特有的問題,進行自定義的異常封裝。

需求:在本程序中,對於除數是負數,也視爲是錯誤的。
當在函數內部出現了throw拋出異常對象,那麼就必需要給對應的處理。
要麼在內部使用try catch處理。
要麼在函數上聲明讓調用者處理。

class FuShuException extends Exception {

}
class Demo {
    int div(int x,int y) throws FuShuException{
        if(y<0) {
            throw new FuShuException();//經過throw關鍵字手動拋出一個自定義異常對象
        }
        return x/y;
    }
}
public class ExceptionDemo5 {
    public static void main(String[] args) {
        Demo d = new Demo();
        try {
            int y = d.div(1,-1);
            System.out.println(y);
        }
        catch (FuShuException e) {
            System.out.println(e.toString());
            System.out.println("除數出現負數了");
        }
    }
}

運行結果

FuShuException
除數出現負數了

咱們能夠發現以上的代碼運行的結果中只有異常的名稱,卻沒有異常的信息。由於咱們並未在自定義的異常中定義具體信息。

定義異常信息

由於父類中已經把異常信息的操做完成了。因此子類只要在構造時,將異常信息傳遞給父類經過super語句,就能夠經過getMessage方法獲取自定義的異常信息。

class FuShuException extends Exception {
    private int value;
    FuShuException(){
        super();
    }
    FuShuException(String message,int value) {
        super(message);
        this.value = value;
    }
    public int getValue() {
        return value;
    }
}
class Demo {
    int div(int x,int y) throws FuShuException{
        if(y<0) {
            throw new FuShuException("--被零除了--",y);//經過throw關鍵字手動拋出一個自定義異常對象
        }
        return x/y;
    }
}
public class ExceptionDemo5 {
    public static void main(String[] args) {
        Demo d = new Demo();
        try {
            int y = d.div(1,-1);
            System.out.println(y);
        }
        catch (FuShuException e) {
            System.out.println(e.toString());
            System.out.println("除數出現了負數:"+e.getValue());
        }
    }
}

運行結果:

FuShuException: --被零除了--
除數出現了負數:-1

注意

自定義異常必須是是自定義類繼承Exception
異常體系中的異常類和異常對象都具有可拋性,這個可拋性是Throwable這個體系中獨有的特色。只有這個體系中的類和對象才能夠被throw和throws操做。

throw和throws的區別

  1. throws使用在函數上,throw使用在函數內。
  2. throws後面跟的是異常類,能夠跟多個用逗號隔開。throw後跟的是異常對象。

RuntimeException

異常分兩種

  1. 編譯時被檢測的異常。
  2. 編譯時不被檢測的異常(運行時的異常。RuntimeException以及其子類)

RuntimeException是Exception中的一個特殊的子類。
若是在函數內容中拋出異常,函數上能夠不用聲明。
若是在函數上聲明瞭異常,調用者能夠不用進行處理。

之因此不用在函數上聲明是由於不須要讓調用者處理,當該異常發生,程序但願中止,對代碼進行修正,而不是去讓調用者處理。

自定義異常時,若是該異常發生,沒法再繼續進行運算,就讓自定義異常繼承RuntimeException。

class FuShuException extends RuntimeException{
    FuShuException(String message) {
        super(message);
    }
}
class Demo {
        int div(int x,int y) {  //函數上爲聲明異常也能夠正常編譯
            if (y < 0) {
                throw new FuShuException("--除數爲負數--");//在函數內容中拋出異常
            }
            else if(y == 0){
                throw new ArithmeticException("--除數爲零--");//在函數內容中拋出異常
            }
            return x/y;
        }
}
public class ExceptionDemo6 {
    public static void main(String[] args) {
        Demo d = new Demo();
        try {
            int y = d.div(1,-1);
        }
        catch (FuShuException e) {
            System.out.println(e.toString());
        }
        catch (ArithmeticException e) {
            System.out.println(e.toString());
        }
    }
}

finally

try {

}
catch () {

}
finally {

}

finally中存放的是必定會被執行(不管是否有異常)的代碼,即便catch中有return語句。

finally只有一種狀況不會被執行,當代碼執行到System.exit(0);

例如:若是須要對數據庫進行操做,不管有沒有成功鏈接上數據庫,在最後操做完成的時候,都須要斷開數據庫的鏈接,以釋放有限的資源。

異常處理語句的另外一種格式

try {
    
}
finally {

}

異常在覆蓋時的特色

  1. 子類在覆蓋父類時,若是父類的方法拋出異常,那麼子類的覆蓋方法只能拋出父類的異常或者該異常的子類。子類程序在繼承時不能拋出新的異常。
  2. 若是父類方法拋出多個異常,那麼子類在覆蓋方法時,只能拋出父類異常的子集。
  3. 若是父類或者接口的方法中沒有異常拋出,那麼子類在覆蓋方法時,也不能夠拋出異常若是子類方法發生了異常,就必需要進行try處理,不能夠拋出。

異常的好處

  1. 將問題進行封裝。
  2. 將正常流程代碼和問題處理代碼相分離,加強代碼可讀性。

    異常的處理原則

  3. 兩種處理方式: try和throws
  4. 調用到拋出異常的功能時,拋出幾個,就須要處理幾個。一個try對應多個catch
  5. 多個catch須要將父類異常的catch放到最下面。
  6. catch內,須要定義針對性處理方式,不要簡單地定義printStackTrace。
    • 當捕獲到地異常,沒法處理,能夠繼續在catch中拋出該沒法處理的異常
    • 若是該異常處理不了,但並不屬於該功能出現的異常,能夠將該異常進行轉換而後再拋出
    • 若是異常能夠處理,但須要使拋出的異常和本功能相關,也能夠對異常進行轉換

異常練習

有圓形和長方形,均可以獲取面積,對於面積,若是出現非法的數值,視爲是獲取面積出現問題。
出現的問題經過異常來表示。(使用異常能夠,使問題處理代碼和正常流程代碼分開)

interface Shape {
    void getArea();
}
class InvaidValueException extends RuntimeException {//若是一個傳入一個圖形的參數有錯誤,咱們沒法對其進行有效的處理,只拋出異常便可,因此繼承RuntimeException
    InvaidValueException(String message) {
        super(message);
    }
}
class Rec implements Shape {
    private double len,wid;
    Rec(double len,double wid) {
        if(len <= 0 || wid <= 0)
                throw new InvaidValueException("非法值");
        this.len = len;
        this.wid = wid;
    }
    @Override
    public void getArea() {
        System.out.println(wid*len);
    }
}

class Circle implements Shape {
    private double r;
    public static final double PI = 3.14;
    Circle(double r)  {
        if(r <= 0)
            throw new InvaidValueException("非法值");
        this.r = r;
    }
    @Override
    public void getArea() {
        System.out.println(r*r*PI);
    }
}
public class ExceptionDemo7 {
    public static void main(String[] args) {
        Rec R = new Rec(1,2);
        R.getArea();
        Circle C = new Circle(-1);
        C.getArea();
        System.out.println("over");
    }
}

上述程序的運行結果爲:

2.0
Exception in thread "main" InvaidValueException: 非法值
    at Circle.<init>(ExceptionDemo7.java:28)
    at ExceptionDemo7.main(ExceptionDemo7.java:41)
相關文章
相關標籤/搜索