《Java編程思想》 -- 異常總結

概述

提及異常,我就想起了Bug,也就是常說的信春哥,無Bug,什麼是Bug呢?我理解的Bug就是沒有按照本身原先假想的邏輯去執行,這其中包括了兩個方面,一方面是代碼語法問題,一方面是邏輯問題,就好比正常邏輯買了東西要付款,可是買家買了東西卻沒有付款,直接拿東西走了,這是邏輯問題,或者是原本數組存儲3個元素,你卻存了4個,這時候也出現了Bug,程序報錯了,這種Bug就是異常。
異常也是Java類的一種,用new建立對象,他們的結構是這樣的:java

  • Throwable程序員

    • error面試

    • Exception編程

恩,就是這樣,異常分爲錯誤和異常,感受有點繞口,但就是這樣,像error這種錯誤是在編譯期間就會報出來的,若是你使用的是IDE,因此咱們只須要關注Exception異常就能夠了。數組

獲取異常和處理異常

獲取和處理異常可能就是異常的所有,咱們的一個原則就是:學習

  • 發生異常就得讓程序員知道this

獲取異常

怎麼獲取異常呢?Java給出了try關鍵字用來解決,咱們只須要將可能出現異常的代碼放在try中就能夠了,就像這樣:日誌

try{
        ...
    }

java給出了儘可能優雅的解決方案來處理異常,它不但願處理異常的代碼和自己的業務代碼有過多的混合,獲取到異常就該處理異常,這時候就應該這樣寫了:code

try{
        ...
    }catch(Type1 type1){
        ...
    }catch(Type2 type2){
        ...
    }
  • catch中的type表明了在try中可能出現的異常類型對象

catch如何匹配異常?

  • 按順序從第一個到最後一個,若是發現異常匹配,就中止匹配,和switch模式不同

  • 基類包含子類異常,若是第一個是Exception,那麼後面的都不用匹配了

那麼catch中怎麼處理這個異常呢?

  • 不做處理(會出現「吞食」)

  • 打印到控制檯

  • 寫入日誌

  • 繼續向上拋

在try塊中拋出異常,咱們在catch中會匹配到相應的異常類型,這時候咱們就會拿到對應的異常對象的引用,咱們調用throwalbe的方法用於處理:

public class ExceptionMethods {
    public static void main(String[] args) {
        try {
            throw new Exception("My Exception");
        } catch (Exception e) {
            System.out.println("Caught Exception");
            System.out.println(e.getMessage());
            System.out.println(e.getLocalizedMessage());
            System.out.println(e);
            System.out.println(e.toString());
            e.printStackTrace();
            e.printStackTrace(System.out);
        }
    }
}
  • 咱們通常使用e.printStackTrace();打出異常棧信息便可

  • 或者是寫入Log,使用logger.error

  • 每一個人處理處理異常的方式可能不盡相同

咱們除了可使用try來捕獲異常,咱們也能夠將這個異常拋出去,咱們能夠把異常比做如今這種制度,地球村出了點問題,村長衡量了一下,以爲這事情本身處理不了,就交給鄉長了,這種把問題交給上層或者是Java編程思想中說的跳出當前環境,交給一個更大的環境去處理,這也是Java異常處理的一種思路。

if(t == null)
    throw new NullPointerException();

其實異常最重要的就是異常的名稱,如今Java正在擴充異常的種類,可是不少異常可能不是咱們想要的,那麼咱們就能夠自定義異常:

class SystemErrException extends Exception{

}

這就是一個異常類,咱們繼承了Exception,這個SysteErrException就能夠用於咱們處理異常的時候了,固然咱們能夠給他加點參數:

class SystemErrException extends Exception{
    public SystemErrException(){ 
    }
    public SystemErrException (String message){
        super(message);
    }
}

或者是這樣:

class SystemErrException extends Exception{
    private int i;
    public SystemErrException(){ 
    }
    public SystemErrException (String message){
        super(message);
    }
    public SystemErrException (String message, int i){
        super(message);
        this.i = i;
    }
}
  • 這只不過是多加了幾個參數,可是這些通常是沒什麼必要的。

throws

說到這,就得說另外一個關鍵字throws,看清楚,不是throw,而是throws,這可能也是面試新手的時候會問的一個問題,throws是異常中的一個申明,在IO學習中會很是常見,它是一個聲明,編譯器檢查到說你這段代碼可能會發生什麼異常,你要聲明一下,這時候你就要在方法上聲明:

public void inputFile() throws IOException{
    ....
}

finally

finally用處就和他的意思相符,表示最終的含義,也就是finally裏面的代碼必定會獲得執行:
案例一

public class FinallyException {
    static int count = 0;

    public static void main(String[] args) {
        while (true){
            try {
                if (count++ == 0){
                    throw new ThreeException();
                }
                System.out.println("no Exception");
            }catch (ThreeException e){
                System.out.println("ThreeException");
            }finally {
                System.out.println("in finally cause");
                if(count == 2)
                    break;
            }
        }
    }
}

class ThreeException extends Exception{

}

執行結果:

ThreeException
in finally cause
no Exception
in finally cause

案例二:return案例

public class MultipleReturns {

    public static void f(int i){
        System.out.println("start.......");
        try {
            System.out.println("1");
            if(i == 1)
                return;
            System.out.println("2");
            if (i == 2)
                return;
            System.out.println("3");
            if(i == 3)
                return;
            System.out.println("else");
            return;
        }finally {
            System.out.println("end");
        }
    }

    public static void main(String[] args) {
        for (int i = 1; i<4; i++){
            f(i);
        }
    }
}

執行結果:

start.......
1
end
start.......
1
2
end
start.......
1
2
3
end

最佳實踐

咱們可能遇到這種狀況,打開一個文件,讀取文件,關閉文件,正常邏輯是這樣的,可是這樣會有幾個問題:

  • 在打開文件的過程當中出現異常,可是還要關閉文件

就像這樣:

try{
        A a = new A();
        ...
    }catch(){
        ...
    }finally{
        a.close();
    }
  • A在建立過程當中會出現異常,可是仍是會執行a的方法,好比關閉文件

因此咱們應該這麼作:

try{
        A a = new A();
        try{
            ...
        }finally{
            a.close();
        }
    }catch(){
        ...
    }

異常棧

通常報錯都會報一大堆錯誤,你們無從看起,其實異常報錯也是有規律的,這就是棧結構,先進後出,舉個栗子:

public class WhoCalled {
    static void f() {
        try {
            throw new Exception();
        } catch (Exception e) {
            for (StackTraceElement ste : e.getStackTrace()){
                System.out.println(ste.getMethodName());
            }
        }
    }

    static void g(){
        f();
    }

    static void h(){
        g();
    }


    public static void main(String[] args) {
        f();
        System.out.println("---------------------------");
        g();
        System.out.println("---------------------------");
        h();
        System.out.println("---------------------------");

    }
}

運行結果:

f
main
---------------------------
f
g
main
---------------------------
f
g
h
main
---------------------------

能夠看到異常信息都是從內到外的,按個人理解查看異常的時候要從第一條異常信息看起,由於那是異常發生的源頭。

總結

異常總的來講仍是很重要的,也是保障程序健壯性很重要的一欄,而且能夠達到立竿見影的效果,這裏只是基本總結了異常的一些常見問題,不少還得在本身運用的過程當中去探索。

相關文章
相關標籤/搜索