1. 程式人生 > >java學習筆記(八)-- 異常

java學習筆記(八)-- 異常

異常體系圖

  • Error:描述Java執行時內部錯誤與資源耗盡錯誤(OOM,StackOverflow)應用程式不丟擲此類異常。這種內部錯誤一旦出現,除了告知使用者並使用安全終止之外,再無能為力。
  • Exception(程式本身錯誤):Java應用程式丟擲異常。
  • IOException:程式本身沒有問題,由於IO處理導致的程式出錯。
  • RuntimeExcpetion:執行時異常

關於受查異常和非受查異常

  • 非受查異常(無須強制處理):所有繼承於Error或RuntimeException的異常類稱為非受查異常(執行時異常)。比如:NullPointerException,ClassCastException,ArrayIndexsOutOfBoundsException,ArithmeticException(算術異常,除0溢位)
  • 受查異常(呼叫處必須強制處理):所有繼承於Exception與IOException的類稱為受查異常(編譯器異常)比如:Exception,FileNotFoundException,IOException,SQLException.

異常處理格式:

try{
    可能出現異常的語句(error類)
}[catch(異常類 物件)]{
    出異常的操作          (Exception類)
}[finally]{
    異常出口
}
try...catch
try...finally
try...catch...finally...

範例·:當你知道產生異常的原因,位置,可以直接輸出異常類物件,或者呼叫所有異常類中提供的printStackTrace()方法進行完整異常資訊的輸出。

public class Test {
    public static void main(String[] args) {
        System.out.println("1.數學計算開始前");
        //產生異常
        System.out.println("2.數學計算:"+10/0);
        System.out.println("3.數學計算結束後");
    }
}
//數字除零異常
//ArithmeticException

異常處理:使用try...catch...

public class Test {
    public static void main(String[] args) {
        System.out.println("1.數學計算開始前");
        //處理產生異常
        try {
        System.out.println("2.數學計算:"+10/0);
        } catch (ArithmeticException e) {
            System.out.println("異常已經被處理");    
            //e.printStackTrace();  列印異常錯誤堆疊
        }
        System.out.println("3.數學計算結束後");
    }
}
/*
1.數學計算開始前
異常已經被處理
3.數學計算結束後
*/

異常處理:使用try...catch...finally

public class Test {
    public static void main(String[] args) {
        System.out.println("1.數學計算開始前");
        //處理產生異常
        try {
            System.out.println("2.數學計算:" + 10 / 0);
        } catch (ArithmeticException e) {
            e.printStackTrace();
        } finally {
            System.out.println("[finally]不論是否產生異常,都執行此句");
        }
        System.out.println("3.數學計算結束後");
    }
}
/*
1.1.數學計算開始前
java.lang.ArithmeticException: / by zero
at www.Dyson.java.Test.main(Test.java:8)
[finally]不論是否產生異常,都執行此句
3.數學計算結束後
*/

**** 重要 ****

範例:關於finally執行順序問題,最終返回值問題   在JVM執行finally塊中的return會覆蓋之前的return

public class Test{
    public static void main(String[] args) {
        System.out.println(test());
    }
    public static int test(){
        try {
            System.out.println("try塊....");
            return 1;
        } catch (Exception e) {
            System.out.println("catch塊....");
            return 2;
        } finally {
            System.out.println("finally塊....");
            return 3;
        }
    }
}
/*
finally是必執行,不會因為前面的return而提前返回
try塊....
finally塊....
3
*/

範例:初始化引數進行數學運算

public class Test {
    public static void main(String[] args) {
        System.out.println("1.數學計算開始前");
        //處理產生異常
        try {
            int x=Integer.parseInt(args[0]);
            int y=Integer.parseInt(args[1]);
            System.out.println("2.進行數學運算:"+x/y);
        } catch (ArithmeticException e) {
            e.printStackTrace();
        } finally {
            System.out.println("[finally]不論是否產生異常,都執行此句");
        }
        System.out.println("3.數學計算結束後");
    }
}

當我們要處理該異常時就會發現,異常產生的原因還可邊的 比如:

  • 使用者沒有初始化引數:ArrayIndexOutOfBoundsException (陣列越界異常)

  • 使用者輸入的不是數字:NumberFormatException (數字格式化異常)

  • 除數為0:ArithmeticException (除零異常)

  • 當catch沒有捕獲到異常時,程式仍然無法進行處理,這時我們就可以使用多個catch

範例:Integer.parselnt(argsp[0]) 將String類變成int

public class Test {
    public static void main(String[] args) {
        System.out.println("1.數學計算開始前");
        //處理產生異常
        try {
            int x=Integer.parseInt(args[0]);
            int y=Integer.parseInt(args[1]);
            System.out.println("2.進行數學運算:"+x/y);
        } catch (ArithmeticException e) {
            e.printStackTrace();
        } catch (NumberFormatException e){
            e.printStackTrace();
        } catch (ArrayIndexOutOfBoundsException e){
            e.printStackTrace();
        }
        //在多異常的情況下,給一個共同的父類Exception
        //catch (Exception e){
        //    e.printStackTrace();
        //}
        finally {
            System.out.println("[Finally]不管是否產生異常,都執行此語句" );
        }
        System.out.println("3.數學計算結束後");
    }
}
/*
1.數學計算開始前
[Finally]不管是否產生異常,都執行此語句
3.數學計算結束後
java.lang.ArrayIndexOutOfBoundsException: 0
    at www.Dyson.java.Test.main(Test.java:8)
*/

ctrl + alt + t   異常包檔案

  • 無論是否產生異常,無論try catch是否有返回語句,最終都會執行finally塊。處理程式退出以外的所有情況,finally都會執行如果你知道程式產生的原因並且異常較少的情況下,建議使用catch具體異常的原因,這樣方法別人閱讀原始碼如果以後程式程式碼可能出現多個異常或者根本不知道會產生何種異常,可以catch共同父類Exception,而後呼叫printStackTrace()顯示出現何種異常
  • 打印出錯後異常堆疊  打印出錯堆疊方法:e.printStackTrace();

throws關鍵字--作用於方法上

  • 在進行方法定義時。如果要明確告訴呼叫者本方法可能產生哪些異常,可以使用throws方法進行宣告,表示將異常拋回給呼叫方法。並且當方法出現問題後可以不進行處理。
  • 如要呼叫throws宣告的方法,那麼在呼叫時必須try...catch..進行捕獲,由於該方法有可能產生異常,所以必須按照異常的方式進行處理

範例:使用throws產生異常物件

public class Test {
    public static void main(String[] args) {
        System.out.println("1.數學計算開始前");
        try {
            System.out.println(calculate(10,0));
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("3.數學計算結束後");
    }
//在方法上throws異常,表示本方法可能產生異常但不處理,交由呼叫處處理
    public static int calculate(int x,int y) throws Exception{
        return x/y;
    }
}
/*
1.數學計算開始前
java.lang.ArithmeticException: / by zero
at www.Dyson.java.Test.calculate(Test.java:14)
at www.Dyson.java.Test.main(Test.java:7)
3.數學計算結束後
*/

throw關鍵字--用在方法中

  • throw語句直接寫在方法之中,表示人為進行異常的丟擲。
  • 如果異常物件不希望由JVM產生而通過使用者產生,就可以使用throw語句來完成。
public class Test {
    public static void main(String[] args) {
        try {
            throw new Exception("自己定義的異常");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
/*
1.數學計算開始前
java.lang.Exception: 自己定義的異常
at www.Dyson.java.Test.main(Test.java:6)
*/

面試題:請解釋throw和throws的區別

  • throw用於方法內部,主要表示手工異常丟擲,一般與自定義異常類搭配

  • throws主要在方法宣告上使用,明確告訴使用者本方法可能產生的異常,同時該方法可能不處理此異

異常處理標準格式

範例:現在要求編寫一個方法進行除法操作,但是對於此方法有如下要求

  1. 在進行除法計算操作之前列印一行語句"**********"

  2. 如果在除法計算過程中出現錯誤,則應該將異常返回給呼叫處

  3. 不管最終是否有異常產生,都要求列印一行計算結果資訊

使用try...catch...finally

public class Test {
    public static void main(String[] args) {
        try {
            System.out.println(calculate(10,0));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static int calculate(int x,int y) throws Exception{
        int result=0;
        System.out.println("1.計算開始***********");
        try {
            result=x/y;
        } catch (Exception e) {
            //將異常拋給調用出
            throw e;
        } finally {
            System.out.println("2.計算結束-----------");
        }
        return result;
    }
}
/*
1.計算開始***********
java.lang.ArithmeticException: / by zero
2.計算結束-----------
at www.Dyson.java.Test.calculate(Test.java:14)
at www.Dyson.java.Test.main(Test.java:5)
*/

簡化版:使用try...finally

public class Test {
    public static void main(String[] args) {
        try {
            System.out.println(calculate(10,0));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static int calculate(int x,int y) throws Exception{
        int result=0;
        System.out.println("1.計算開始***********");
        try {
            result=x/y;
        } finally {
            System.out.println("2.計算結束-----------");
        }
        return result;
    }
}
/*
java.lang.ArithmeticException: / by zero
1.計算開始***********
2.計算結束-----------
at www.Dyson.java.Test.calculate(Test.java:14)
at www.Dyson.java.Test.main(Test.java:5)
*/

面試題:請解釋Exception與RuntimeException的區別,請列舉幾個常見的RuntimeException:

  • 使用Exception是RuntimeException的父類,使用Exception定義的異常都要求必須使用異常處理(受查),而使用 RuntimeException定義的異常可以由使用者選擇性的來進行異常處理(非受查)。

  • 常見的RuntimeException:ClassCastException(型別轉化異常)、NullPointerException(空指標異常),陣列越界等。