程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> Java提高篇——Java 異常處理,java提高異常處理

Java提高篇——Java 異常處理,java提高異常處理

編輯:JAVA綜合教程

Java提高篇——Java 異常處理,java提高異常處理


異常的概念

異常是程序中的一些錯誤,但並不是所有的錯誤都是異常,並且錯誤有時候是可以避免的。

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

異常發生的原因有很多,通常包含以下幾大類:

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

這些異常有的是因為用戶錯誤引起,有的是程序錯誤引起的,還有其它一些是因為物理錯誤引起的。-

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

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

 

異常指不期而至的各種狀況,如:文件找不到、網絡連接失敗、除0操作、非法參數等。異常是一個事件,它發生在程序運行期間,干擾了正常的指令流程。

Java語言在設計的當初就考慮到這些問題,提出異常處理的框架的方案,所有的異常都可以用一個異常類來表示,不同類型的異常對應不同的子類異常(目前我們所說的異常包括錯誤概念),定義異常處理的規范,在JDK1.4版本以後增加了異常鏈機制,從而便於跟蹤異常。

Java異常是一個描述在代碼段中發生異常的對象,當發生異常情況時,一個代表該異常的對象被創建並且在導致該異常的方法中被拋出,而該方法可以選擇自己處理異常或者傳遞該異常。

異常的體系結構

Java把異常當作對象來處理,並定義一個基類java.lang.Throwable作為所有異常的超類。

在Java API中已經定義了許多異常類,這些異常類分為兩大類,錯誤Error和異常Exception

Java異常層次結構圖如下圖所示:

從圖中可以看出所有異常類型都是內置類Throwable的子類,因而Throwable在異常類的層次結構的頂層。

接下來Throwable分成了兩個不同的分支,一個分支是Error,它表示不希望被程序捕獲或者是程序無法處理的錯誤另一個分支是Exception,它表示用戶程序可能捕捉的異常情況或者說是程序可以處理的異常。其中異常類Exception又分為運行時異常(RuntimeException)和非運行時異常。

Java異常又可以分為不受檢查異常(Unchecked Exception)和檢查異常(Checked Exception)。

 

下面將詳細講述這些異常之間的區別與聯系:

  • ErrorError類對象由 Java 虛擬機生成並拋出,大多數錯誤與代碼編寫者所執行的操作無關。例如,Java虛擬機運行錯誤(Virtual MachineError),當JVM不再有繼續執行操作所需的內存資源時,將出現 OutOfMemoryError。這些異常發生時,Java虛擬機(JVM)一般會選擇線程終止;還有發生在虛擬機試圖執行應用時,如類定義錯誤(NoClassDefFoundError)、鏈接錯誤(LinkageError)。這些錯誤是不可查的,因為它們在應用程序的控制和處理能力之 外,而且絕大多數是程序運行時不允許出現的狀況。對於設計合理的應用程序來說,即使確實發生了錯誤,本質上也不應該試圖去處理它所引起的異常狀況。在Java中,錯誤通常是使用Error的子類描述。
  • Exception:在Exception分支中有一個重要的子類RuntimeException(運行時異常),該類型的異常自動為你所編寫的程序定義ArrayIndexOutOfBoundsException(數組下標越界)、NullPointerException(空指針異常)、ArithmeticException(算術異常)、MissingResourceException(丟失資源)、ClassNotFoundException(找不到類)等異常,這些異常是不檢查異常,程序中可以選擇捕獲處理,也可以不處理。這些異常一般是由程序邏輯錯誤引起的,程序應該從邏輯角度盡可能避免這類異常的發生;而RuntimeException之外的異常我們統稱為非運行時異常,類型上屬於Exception類及其子類,從程序語法角度講是必須進行處理的異常,如果不處理,程序就不能編譯通過。如IOExceptionSQLException等以及用戶自定義的Exception異常,一般情況下不自定義檢查異常。

 注意

ErrorException的區別:Error通常是災難性的致命的錯誤,是程序無法控制和處理的,當出現這些異常時,Java虛擬機(JVM)一般會選擇終止線程;Exception通常情況下是可以被程序處理的,並且在程序中應該盡可能的去處理這些異常。

  • 檢查異常:在正確的程序運行過程中,很容易出現的、情理可容的異常狀況,在一定程度上這種異常的發生是可以預測的,並且一旦發生該種異常,就必須采取某種方式進行處理。

♠提示

除了RuntimeException及其子類以外,其他的Exception類及其子類都屬於檢查異常,當程序中可能出現這類異常,要麼使用try-catch語句進行捕獲,要麼用throws子句拋出,否則編譯無法通過。

  • 不受檢查異常包括RuntimeException及其子類和Error

♠提示

不受檢查異常為編譯器不要求強制處理的異常,檢查異常則是編譯器要求必須處置的異常。

Java 異常的處理機制

Java的異常處理本質上是拋出異常捕獲異常

  • 拋出異常:要理解拋出異常,首先要明白什麼是異常情形(exception condition),它是指阻止當前方法或作用域繼續執行的問題。其次把異常情形和普通問題相區分,普通問題是指在當前環境下能得到足夠的信息,總能處理這個錯誤。對於異常情形,已經無法繼續下去了,因為在當前環境下無法獲得必要的信息來解決問題,你所能做的就是從當前環境中跳出,並把問題提交給上一級環境,這就是拋出異常時所發生的事情。拋出異常後,會有幾件事隨之發生。首先,是像創建普通的java對象一樣將使用new在堆上創建一個異常對象;然後,當前的執行路徑(已經無法繼續下去了)被終止,並且從當前環境中彈出對異常對象的引用。此時,異常處理機制接管程序,並開始尋找一個恰當的地方繼續執行程序,這個恰當的地方就是異常處理程序或者異常處理器,它的任務是將程序從錯誤狀態中恢復,以使程序要麼換一種方式運行,要麼繼續運行下去。

舉個簡單的例子,假使我們創建了一個學生對象Student的一個引用stu,在調用的時候可能還沒有初始化。所以在使用這個對象引用調用其他方法之前,要先對它進行檢查,可以創建一個代表錯誤信息的對象,並且將它從當前環境中拋出,這樣就把錯誤信息傳播到更大的環境中。

if(stu == null){
    throw new NullPointerException();
}

這就拋出了異常,它將在其他的地方得到執行或者處理,具體是哪個地方後面將很快介紹,代碼中出現的 throw 是一個關鍵字,暫時先不做過多講解,後面會詳細講解。

  • 捕獲異常:在方法拋出異常之後,運行時系統將轉為尋找合適的異常處理器(exception handler)。潛在的異常處理器是異常發生時依次存留在調用棧中的方法的集合。當異常處理器所能處理的異常類型與方法拋出的異常類型相符時,即為合適的異常處理器。運行時系統從發生異常的方法開始,依次回查調用棧中的方法,直至找到含有合適異常處理器的方法並執行。當運行時系統遍歷調用棧而未找到合適的異常處理器,則運行時系統終止。同時,意味著Java程序的終止。

 提示

對於運行時異常錯誤檢查異常,Java技術所要求的異常處理方式有所不同。

由於運行時異常及其子類的不可查性,為了更合理、更容易地實現應用程序,Java規定,運行時異常將由Java運行時系統自動拋出,允許應用程序忽略運行時異常

對於方法運行中可能出現的Error,當運行方法不欲捕捉時,Java允許該方法不做任何拋出聲明。因為,大多數Error異常屬於永遠不能被允許發生的狀況,也屬於合理的應用程序不該捕捉的異常。

對於所有的檢查異常,Java規定:一個方法必須捕捉,或者聲明拋出方法之外。也就是說,當一個方法選擇不捕捉檢查異常時,它必須聲明將拋出異常。

Java異常處理涉及到五個關鍵字,分別是:trycatchfinallythrowthrows。下面將驟一介紹,通過認識這五個關鍵字,掌握基本異常處理知識。

  • try        -- 用於監聽。將要被監聽的代碼(可能拋出異常的代碼)放在try語句塊之內,當try語句塊內發生異常時,異常就被拋出。
  • catch   -- 用於捕獲異常。catch用來捕獲try語句塊中發生的異常。
  • finally  -- finally語句塊總是會被執行。它主要用於回收在try塊裡打開的物力資源(如數據庫連接、網絡連接和磁盤文件)。只有finally塊,執行完成之後,才會回來執行try或者catch塊中的return或者throw語句,如果finally中使用了return或者throw等終止方法的語句,則就不會跳回執行,直接停止。
  • throw   -- 用於拋出異常。
  • throws -- 用在方法簽名中,用於聲明該方法可能拋出的異常。

異常處理的基本語法

1. try-catch

try{
    //code that might generate exceptions    
}catch(Exception e){
    //the code of handling exception1
}catch(Exception e){
    //the code of handling exception2
}

要明白異常捕獲,還要理解監控區域(guarded region)的概念。它是一段可能產生異常的代碼,並且後面跟著處理這些異常的代碼。

因而可知,上述try-catch所描述的即是監控區域,關鍵詞try後的一對大括號將一塊可能發生異常的代碼包起來,即為監控區域。Java方法在運行過程中發生了異常,則創建異常對象。將異常拋出監控區域之外,由Java運行時系統負責尋找匹配的catch子句來捕獲異常。若有一個catch語句匹配到了,則執行該catch塊中的異常處理代碼,就不再嘗試匹配別的catch塊了。

匹配的原則是:如果拋出的異常對象屬於catch子句的異常類,或者屬於該異常類的子類,則認為生成的異常對象與catch塊捕獲的異常類型相匹配。

舉個例子算術異常:

public class TestException {  
    public static void main(String[] args) {  
        int a = 1;  
        int b = 0;  
        try { // try監控區域               
            if (b == 0) throw new ArithmeticException(); // 通過throw語句拋出異常  
            System.out.println("a/b的值是:" + a / b);  
            System.out.println("this will not be printed!");
        }  
        catch (ArithmeticException e) { // catch捕捉異常  
            System.out.println("程序出現異常,變量b不能為0!");  
        }  
        System.out.println("程序正常結束。");  
    }  
}  

運行結果:

D:\java>java TestException
 
程序出現異常,變量b不能為0!

程序正常結束。

顯示一個異常的描述,Throwable重載了toString()方法(由Object定義),所以它將返回一個包含異常描述的字符串。例如,將前面的catch塊重寫成:

catch (ArithmeticException e) { // catch捕捉異常  
    System.out.println("程序出現異常"+e);  
} 

結果:

D:\java>java TestException

程序出現異常java.lang.ArithmeticException

程序正常結束。

根據前面講述的,算術異常屬於運行時異常,因而實際上該異常不需要程序拋出,運行時系統自動拋出,將例子改為如下:

public class TestException {  
    public static void main(String[] args) {  
        int a = 1;  
        int b = 0;    
        System.out.println("a/b的值是:" + a / b);
        System.out.println("this will not be printed!");
    }  
}  

結果:

D:\java>java TestException

Exception in thread "main" java.lang.ArithmeticException: / by zero
    at TestException.main(TestException.java:7)

使用多重的catch語句:很多情況下,由單個的代碼段可能引起多個異常。處理這種情況,我們需要定義兩個或者更多的catch子句,每個子句捕獲一種類型的異常,當異常被引發時,每個catch子句被依次檢查,第一個匹配異常類型的子句執行,當一個catch子句執行以後,其他的子句將被旁路。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved