java異常處理機制主要依賴於try,catch,finally,throw,throws五個關鍵字。
try 關鍵字後緊跟一個花括弧括起來的代碼塊,簡稱try塊。同理:下面的也被稱為相應的塊。
它裡面可置引發異常的代碼。catch後對應異常類型和一個代碼塊,用於表明catch塊用於處理這種類型的代碼塊。後還可以跟一個finally塊,finally塊用於回收在try塊裡開啟的實體資源,異常機制會保證finally塊總被執行。throws關鍵字主要在方法簽名中使用,用於聲明該方法可能拋出的異常,而throw則用於拋出一個實際的異常,throw可以單獨作為語句使用,拋出一個具體的異常的對象 java異常處理可以讓程式具有更好的容錯性,程式更加健壯。當程式 出現意外情形時,系統會自動產生一個Exception對象來通知程式,從而實現將“業務功能實現代碼”和“錯誤處理代碼”分離,提供更好的可讀性。 如果執行try塊裡的商務邏輯代碼時出現異常,系統自動會產生一個異常對象,該異常對象被提交給java運行環境,這個過程被稱為拋出(throw)異常。當java運行環境收到異常對象時,會尋找處理該異常對象的catch塊,如果找到合適的catch塊並把該異常交給它處理,該過程被稱為捕獲異常;如果java運行環境找不到捕獲異常的catch塊,則運行環境終止,程式也將退出。 使用finally回收實體資源 當程式在try塊裡開啟了的一些實體資源(資料庫連接,網路連接及磁碟檔案),這些實體資源必須顯示回收。 為了保證一定能夠回收try塊中開啟的實體資源,異常處理機制提供了finally塊,無論try塊中的代碼是否出現異常,也不管在哪個catch塊中被執行,finally塊總會被執行。異常處理結構文法中只有try塊是必須的,一旦沒有try塊,則不能出現catch和finally塊,如果存在try塊,則catch塊和finally塊都是可選的。但二者至少要出現其一。也可以同時出現多個catch塊。catch塊必須位於try塊後面,而finally必須位於catch塊後面(如果存在的話); 當java程式執行try塊,catch塊,時遇到了return語句或throw語句,這兩個語句都會導致該方法的立即結束,但是系統並不會立即執行這兩個語句,而是去尋找該異常處理流程中是否包含finally塊,如果沒有finally塊程式立即執行return語句或throw語句,方法終止。反之,則系統會立即執行finally塊——只有當finally塊執行完後,系統才會再次跳回來執行try塊,catch塊裡的return或throw語句,如果同時在 finally塊中也存在return或throw語句,則finally塊已經終止了方法,自然不存在系統再次跳轉去執行try或catch塊裡的return或throw語句。 使用throws聲明拋出異常的思路是:當前方法不知道應該如何處理這種異常,該異常應該由上一級調用者處理,如果main方法也不知道如何處理這種異常類型。也可以使用throws聲明拋出異常,把該異常交給javaJVM處理。 JVM對異常的處理方法:列印異常跟蹤棧資訊,並終止程式運
runtime exception和checked exception
Java提供了兩類主要的異常:runtime
exception和checked exception。所有的checked exception是從java.lang.Exception類衍生出來的,而runtime exception則是從java.lang.RuntimeException或java.lang.Error類衍生出來的。
它們的不同之處表現在兩方面:機制上和邏輯上。
一、機制上
它們在機制上的不同表現在兩點:1.如何定義方法;2. 如何處理拋出的異常。 * Runtime exceptions:
在定義方法時不需要聲明會拋出runtime exception;
在調用這個方法時不需要捕獲這個runtime exception;
runtime exception是從java.lang.RuntimeException或java.lang.Error類衍生出來的。
* Checked exceptions:
定義方法時必須聲明所有可能會拋出的checked exception;
在調用這個方法時,必須捕獲它的checked exception,不然就得把它的exception傳遞下去;
checked exception是從java.lang.Exception類衍生出來的。 二、邏輯上
從邏輯的角度來說,checked exceptions和runtime exception是有不同的使用目的的。checked exception用來指示一種調用方能夠直接處理的異常情況。而runtime exception則用來指示一種調用方本身無法處理或恢複的程式錯誤。
checked exception迫使你捕獲它並處理這種異常情況。以java.net.URL類的構建器(constructor)為例,它的每一個構建器都會拋出MalformedURLException。MalformedURLException就是一種checked exception。設想一下,你有一個簡單的程式,用來提示使用者輸入一個URL,然後通過這個URL去下載一個網頁。如果使用者輸入的URL有錯誤,構建器就會拋出一個exception。既然這個exception是checked
exception,你的程式就可以捕獲它並正確處理:比如說提示使用者重新輸入。 總而言之,在程式的運行過程中一個checked exception被拋出的時候,只有能夠適當處理這個異常的調用方才應該用try/catch來捕獲它。而對於runtime exception,則不應當在程式中捕獲它。如果你要捕獲它的話,你就會冒這樣一個風險:程式碼的錯誤(bug)被掩蓋在運行當中無法被察覺。因為在程式測試過程中,系統列印出來的呼叫堆疊路徑(StackTrace)往往使你更快找到並修改代碼中的錯誤。有些程式員建議捕獲runtime
exception並紀錄在log中,我反對這樣做。這樣做的壞處是你必須通過瀏覽log來找出問題,而用來測試程式的測試系統(比如Unit Test)卻無法直接捕獲問題並報告出來。 針對 RuntimeException 類型的異常, javac
是無法通過編譯時間的靜態文法檢測來判斷到底哪些函數(或哪些地區的代碼)可能拋出這類異常(這完全取決於運行時狀態,或者說運行態所決定的)理解為non_checked可以?,也正因為如此, Java 異常處理模型中的“ must be caught or declared to be thrown ”規則也不適用於 RuntimeException (所以才有前面所提到過的奇怪編譯現象,這也屬於特殊規則吧)。但是,
JAVA 虛擬機器卻需要有效地捕獲並處理此類異常。當然, RuntimeException 也可以被程式員顯式地拋出,而且為了程式的可靠性,對一些可能出現“運行時異常( RuntimeException )”的代碼地區,程式員最好能夠及時地處理這些意外的異常,也即通過 catch(RuntimeExcetion) 或 catch(Exception) 來捕獲它們。
總結:
所有異常的根類為java.lang.Throwable,Throwable下面又派生了兩個子類:Error和Exception。error表示恢複不是不可能但很困難情況下的一種嚴重的問題。比如說記憶體溢出,不可能指望程式處理這樣的情況,exception表示一種設計或實現問題,也就是說,它表示如果程式運行正常,從不會發生的情況。
異常表示程式運行過程中可能出現的非正常狀態,運行時異常表示虛擬機器的通常操作中可能遇到的異常,是一種常見的運行錯誤。java編譯器要求方法必須聲明拋出可能發生的非運行時異常,但是並不要求必須聲明拋出為被捕獲的運行時異常。