Java異常總結

 本文目錄:html

    一、異常的概念java

    二、java中的異常體系結構程序員

    三、異常基本語法數據庫

    四、jvm對異常的處理編程

    五、異常注意事項數組

1.異常概念

  異常是程序中的一些錯誤,但並非全部的錯誤都是異常,而且錯誤有時候是能夠避免的。 網絡

  好比說,你的代碼少了一個分號,那麼運行出來結果是提示是錯誤 java.lang.Error;若是你用System.out.println(11/0),那麼你是由於你用0作了除數,會拋出 java.lang.ArithmeticException 的異常。 多線程

  異常發生的緣由有不少,一般包含如下幾大類:jvm

    • 用戶輸入了非法數據。
    • 要打開的文件不存在。
    • 網絡通訊時鏈接中斷,或者JVM內存溢出。

  這些異常有的是由於用戶錯誤引發,有的是程序錯誤引發的,還有其它一些是由於物理錯誤引發的。-編程語言

  要理解Java異常處理是如何工做的,你須要掌握如下三種類型的異常:

    • 檢查性異常:最具表明的檢查性異常是用戶錯誤或問題引發的異常,這是程序員沒法預見的。例如要打開一個不存在文件時,一個異常就發生了,這些異常在編譯時不能被簡單地忽略。
    • 運行時異常: 運行時異常是可能被程序員避免的異常。與檢查性異常相反,運行時異常能夠在編譯時被忽略。
    • 錯誤: 錯誤不是異常,而是脫離程序員控制的問題。錯誤在代碼中一般被忽略。例如,當棧溢出時,一個錯誤就發生了,它們在編譯也檢查不到的。

2.java中異常的體系結構

 

  整體上咱們根據Javac對異常的處理要求,將異常類分爲2類:

  非檢查異常(unckecked exception):Error 和 RuntimeException 以及他們的子類。javac在編譯時,不會提示和發現這樣的異常,不要求在程序處理這些異常。因此若是願意,咱們能夠編寫代碼處理(使用try…catch…finally)      這樣的異常,也能夠不處理。對於這些異常,咱們應該修正代碼,而不是去經過異常處理器處理 。這樣的異常發生的緣由多半是代碼寫的有問題。如除0錯誤ArithmeticException,錯誤的強制類型轉換錯誤ClassCastException,數組索引越界ArrayIndexOutOfBoundsException,使用了空對象NullPointerException等等。

  檢查異常(checked exception):除了Error 和 RuntimeException的其它異常。javac強制要求程序員爲這樣的異常作預備處理工做(使用try…catch…finally或者throws)。在方法中要麼用try-catch語句捕獲它並處理,要麼用throws子句聲明拋出它,不然編譯不會經過。這樣的異常通常是由程序的運行環境致使的。由於程序可能被運行在各類未知的環境下,而程序員沒法干預用戶如何使用他編寫的程序,因而程序員就應該爲這樣的異常時刻準備着。如SQLException , IOException,ClassNotFoundException 等。

3.異常處理的基本語法

  ①捕獲

try
{
   // 程序代碼
}catch(ExceptionName e1)
{
   //Catch 塊
}

  Catch 語句包含要捕獲異常類型的聲明。當保護代碼塊中發生一個異常時,try 後面的 catch 塊就會被檢查。

  若是發生的異常包含在 catch 塊中,異常會被傳遞到該 catch 塊,這和傳遞一個參數到方法是同樣。

  ②多重捕獲

  一個 try 代碼塊後面跟隨多個 catch 代碼塊的狀況就叫多重捕獲。

  多重捕獲塊的語法以下所示:

try{
   // 程序代碼
}catch(異常類型1 異常的變量名1){
  // 程序代碼
}catch(異常類型2 異常的變量名2){
  // 程序代碼
}catch(異常類型2 異常的變量名2){
  // 程序代碼
}

  上面的代碼段包含了 3 個 catch塊。

  能夠在 try 語句後面添加任意數量的 catch 塊。

  若是保護代碼中發生異常,異常被拋給第一個 catch 塊。

  若是拋出異常的數據類型與 ExceptionType1 匹配,它在這裏就會被捕獲。

  若是不匹配,它會被傳遞給第二個 catch 塊。

  如此,直到異常被捕獲或者經過全部的 catch 塊

  注意

    a、異常類型的順序先子類後父類。

    b、java中,異常處理的任務就是將執行控制流從異常發生的地方轉移到可以處理這種異常的地方去。也就是說:當一個函數的某條語句發生異常時,這條語句的後面的語句不會再執行,它失去了焦點。執行流跳轉到最近的匹配的異常處理catch代碼塊去執行,異常被處理完後,執行流會接着在「處理了這個異常的catch代碼塊」後面接着執行。
      有的編程語言當異常被處理後,控制流會恢復到異常拋出點接着執行,這種策略叫作:resumption model of exception handling(恢復式異常處理模式 )
      而Java則是讓執行流恢復處處理了異常的catch塊後接着執行,這種策略叫作:termination model of exception handling(終結式異常處理模式)

   ③throws throw關鍵字

  若是一個方法沒有捕獲到一個檢查性異常,那麼該方法必須使用 throws 關鍵字來聲明。throws 關鍵字放在方法簽名的尾部。

  throws是另外一種處理異常的方式,它不一樣於try…catch…finally,throws僅僅是將函數中可能出現的異常向調用者聲明,而本身則不具體處理。

  採起這種異常處理的緣由多是:方法自己不知道如何處理這樣的異常,或者說讓調用者處理更好,調用者須要爲可能發生的異常負責。  

  也可使用 throw 關鍵字拋出一個異常,不管它是新實例化的仍是剛捕獲到的。

  throw 語句必須寫在函數中,執行throw 語句的地方就是一個異常拋出點,它和由JRE自動造成的異常拋出點沒有任何差異

import java.io.*;
public class className
{
  public void deposit(double amount) throws RemoteException
  {
    // Method implementation
    throw new RemoteException();
  }
  //Remainder of class definition
}

  一個方法能夠聲明拋出多個異常,多個異常之間用逗號隔開。

  例如,下面的方法聲明拋出 RemoteException 和 InsufficientFundsException:

  下面方法的聲明拋出一個 RemoteException 異常:

import java.io.*;
public class className
{
   public void withdraw(double amount) throws RemoteException,
                              InsufficientFundsException
   {
       // Method implementation
   }
   //Remainder of class definition
}

  ④finally關鍵字

  finally塊無論異常是否發生,只要對應的try執行了,則它必定也執行。

  只有一種方法讓finally塊不執行:System.exit()。

  所以finally塊一般用來作資源釋放操做:關閉文件,關閉數據庫鏈接等等

  finally 代碼塊出如今 catch 代碼塊最後,語法以下:

try{
  // 程序代碼
}catch(異常類型1 異常的變量名1){
  // 程序代碼
}catch(異常類型2 異常的變量名2){
  // 程序代碼
}finally{
  // 程序代碼
}

  注意下面事項:

    • catch 不能獨立於 try 存在。
    • 在 try/catch 後面添加 finally 塊並不是強制性要求的。
    • try 代碼後不能既沒 catch 塊也沒 finally 塊。
    • try, catch, finally 塊之間不能添加任何代碼。

  ⑤聲明自定義異常

  在 Java 中你能夠自定義異常。編寫本身的異常類時須要記住下面的幾點。

    1. 全部異常都必須是 Throwable 的子類。
    2. 若是但願寫一個檢查性異常類,則須要繼承 Exception 類。
    3. 若是你想寫一個運行時異常類,那麼須要繼承 RuntimeException 類。

  按照國際慣例,自定義的異常應該老是包含以下的構造函數:

    1. 一個無參構造函數
    2. 一個帶有String參數的構造函數,並傳遞給父類的構造函數。
    3. 一個帶有String參數和Throwable參數,並都傳遞給父類構造函數
    4. 一個帶有Throwable 參數的構造函數,並傳遞給父類的構造函數。

  借鑑IOException來定義本身的異常類:

public class IOException extends Exception
{
    static final long serialVersionUID = 7818375828146090155L;
    public IOException()
    {
        super();
    }
    public IOException(String message)
    {
        super(message);
    }
    public IOException(String message, Throwable cause)
    {
        super(message, cause);
    }
    public IOException(Throwable cause)
    {
        super(cause);
    }
}

  ⑥異常鏈

  在一些大型的,模塊化的軟件開發中,一旦一個地方發生異常,則如骨牌效應同樣,將致使一連串的異常。假設B模塊完成本身的邏輯須要調用A模塊的方法,若是A模塊發生異常,則B也將不能完成而發生異常,可是B在拋出異常時,會將A的異常信息掩蓋掉,這將使得異常的根源信息丟失。異常的鏈化能夠將多個模塊的異常串聯起來,使得異常信息不會丟失。

  異常鏈化以一個異常對象爲參數構造新的異常對象。新的異對象將包含先前異常的信息。這項技術主要是異常類的一個帶Throwable參數的函數來實現的。這個當作參數的異常,咱們叫他根源異常(cause)。

  一個鏈化的異常

 1 public static void main(String[] args)
 2 {
 3  
 4     System.out.println("請輸入2個加數");
 5     int result;
 6     try
 7     {
 8         result = add();
 9         System.out.println("結果:"+result);
10     } catch (Exception e){
11         e.printStackTrace();
12     }
13 }
14 //獲取輸入的2個整數返回
15 private static List<Integer> getInputNumbers()
16 {
17     List<Integer> nums = new ArrayList<>();
18     Scanner scan = new Scanner(System.in);
19     try {
20         int num1 = scan.nextInt();
21         int num2 = scan.nextInt();
22         nums.add(new Integer(num1));
23         nums.add(new Integer(num2));
24     }catch(InputMismatchException immExp){
25         throw immExp;
26     }finally {
27         scan.close();
28     }
29     return nums;
30 }
31  
32 //執行加法計算
33 private static int add() throws Exception
34 {
35     int result;
36     try {
37         List<Integer> nums =getInputNumbers();
38         result = nums.get(0)  + nums.get(1);
39     }catch(InputMismatchException immExp){
40         throw new Exception("計算失敗",immExp);  /////////////////////////////鏈化:以一個異常對象爲參數構造新的異常對象。
41     }
42     return  result;
43 }
44  
45 /*
46 請輸入2個加數
47 r 1
48 java.lang.Exception: 計算失敗
49     at practise.ExceptionTest.add(ExceptionTest.java:53)
50     at practise.ExceptionTest.main(ExceptionTest.java:18)
51 Caused by: java.util.InputMismatchException
52     at java.util.Scanner.throwFor(Scanner.java:864)
53     at java.util.Scanner.next(Scanner.java:1485)
54     at java.util.Scanner.nextInt(Scanner.java:2117)
55     at java.util.Scanner.nextInt(Scanner.java:2076)
56     at practise.ExceptionTest.getInputNumbers(ExceptionTest.java:30)
57     at practise.ExceptionTest.add(ExceptionTest.java:48)
58     ... 1 more
59  
60 */
View Code

4.jvm對異常的處理

  待補充

5.異常注意事項

  一、當子類重寫父類的帶有 throws聲明的函數時,其throws聲明的異常必須在父類異常的可控範圍內——用於處理父類的throws方法的異常處理器,必須也適用於子類的這個帶throws方法 。這是爲了支持多態。

   例如,父類方法throws 的是2個異常,子類就不能throws 3個及以上的異常。父類throws IOException,子類就必須throws IOException或者IOException的子類

  二、Java程序能夠是多線程的。每個線程都是一個獨立的執行流,獨立的函數調用棧。若是程序只有一個線程,那麼沒有被任何代碼處理的異常 會致使程序終止。若是是多線程的,那麼沒有被任何代碼處理的異常僅僅會致使異常所在的線程結束。

   也就是說,Java中的異常是線程獨立的,線程的問題應該由線程本身來解決,而不要委託到外部,也不會直接影響到其它線程的執行

  三、首先一個不容易理解的事實:在 try塊中即使有return,break,continue等改變執行流的語句,finally也會執行。

  四、finally中的return 會覆蓋 try 或者catch中的返回值,前提是在finally中從新return了一個變量。

public static void main(String[] args)
    {
        int result;
 
        result  =  foo();
        System.out.println(result);     /////////2
 
        result = bar();
        System.out.println(result);    /////////2
    }
 
    @SuppressWarnings("finally")
    public static int foo()
    {
        trz{
            int a = 5 / 0;
        } catch (Exception e){
            return 1;
        } finally{
            return 2;
        }
 
    }
 
    @SuppressWarnings("finally")
    public static int bar()
    {
        try {
            return 1;
        }finally {
            return 2;
        }
    
View Code

  五、finally中的return會抑制(消滅)前面try或者catch塊中的異常

class TestException
{
    public static void main(String[] args)
    {
        int result;
        try{
            result = foo();
            System.out.println(result);           //輸出100
        } catch (Exception e){
            System.out.println(e.getMessage());    //沒有捕獲到異常
        }
 
        try{
            result  = bar();
            System.out.println(result);           //輸出100
        } catch (Exception e){
            System.out.println(e.getMessage());    //沒有捕獲到異常
        }
    }
 
    //catch中的異常被抑制
    @SuppressWarnings("finally")
    public static int foo() throws Exception
    {
        try {
            int a = 5/0;
            return 1;
        }catch(ArithmeticException amExp) {
            throw new Exception("我將被忽略,由於下面的finally中使用了return");
        }finally {
            return 100;
        }
    }
 
    //try中的異常被抑制
    @SuppressWarnings("finally")
    public static int bar() throws Exception
    {
        try {
            int a = 5/0;
            return 1;
        }finally {
            return 100;
        }
    }
}
View Code

  六、finally中的異常會覆蓋(消滅)前面try或者catch中的異常

class TestException
{
    public static void main(String[] args)
    {
        int result;
        try{
            result = foo();
        } catch (Exception e){
            System.out.println(e.getMessage());    //輸出:我是finaly中的Exception
        }
 
        try{
            result  = bar();
        } catch (Exception e){
            System.out.println(e.getMessage());    //輸出:我是finaly中的Exception
        }
    }
 
    //catch中的異常被抑制
    @SuppressWarnings("finally")
    public static int foo() throws Exception
    {
        try {
            int a = 5/0;
            return 1;
        }catch(ArithmeticException amExp) {
            throw new Exception("我將被忽略,由於下面的finally中拋出了新的異常");
        }finally {
            throw new Exception("我是finaly中的Exception");
        }
    }
 
    //try中的異常被抑制
    @SuppressWarnings("finally")
    public static int bar() throws Exception
    {
        try {
            int a = 5/0;
            return 1;
        }finally {
            throw new Exception("我是finaly中的Exception");
        }
 
    }
}
View Code

  上面的3個例子都異於常人的編碼思惟,所以我建議:

    • 不要在fianlly中使用return。
    • 不要在finally中拋出異常。
    • 減輕finally的任務,不要在finally中作一些其它的事情,finally塊僅僅用來釋放資源是最合適的。
    • 將盡可能將全部的return寫在函數的最後面,而不是try … catch … finally中

本文參考:

  http://www.runoob.com/java/java-exceptions.html

  http://www.importnew.com/26613.html

相關文章
相關標籤/搜索