Java常見異常(Runtime Exception )小結

來源:互聯網
上載者:User
http://www.cnblogs.com/qinqinmeiren/archive/2010/10/14/2151702.html

本文重在Java中異常機制的一些概念。寫本文的目的在於方便我很長時間後若是忘了這些東西可以通過這篇文章迅速回憶起來。
1. 異常機制
1.1 異常機制是指當程式出現錯誤後,程式如何處理。具體來說,異常機制提供了程式退出的安全通道。當出現錯誤後,程式執行的流程發生改變,程式的控制權轉移到異常處理器。

1.2 傳統的處理異常的辦法是,函數返回一個特殊的結果來表示出現異常(通常這個特殊結果是大家約定俗稱的),調用該函數的程式負責檢查並分析函數返回的結果。這樣做有如下的弊端:例如函數返回-1代表出現異常,但是如果函數確實要返回-1這個正確的值時就會出現混淆;可讀性降低,將程式碼與處理異常的代碼混爹在一起;由調用函數的程式來分析錯誤,這就要求客戶程式員對庫函數有很深的瞭解。

1.3 異常處理的流程
1.3.1 遇到錯誤,方法立即結束,並不返回一個值;同時,拋出一個異常對象
1.3.2 調用該方法的程式也不會繼續執行下去,而是搜尋一個可以處理該異常的異常處理器,並執行其中的代碼
2 異常的分類
2.1 異常的分類
2.1.1 異常的繼承結構:基類為Throwable,Error和Exception繼承Throwable,RuntimeException和IOException等繼承Exception,具體的RuntimeException繼承RuntimeException。

2.1.2 Error和RuntimeException及其子類成為未檢查異常(unchecked),其它異常成為已檢查異常(checked)。
2.2 每個類型的異常的特點
2.2.1 Error體系 Error類體系描述了Java運行系統中的內部錯誤以及資源耗盡的情形。應用程式不應該拋出這種類型的對象(一般是由虛擬機器拋出)。如果出現這種錯誤,除了儘力使程式安全退出外,在其他方面是無能為力的。所以,在進行程式設計時,應該更關注Exception體系。

2.2.2 Exception體系 Exception體系包括RuntimeException體系和其他非RuntimeException的體系
2.2.2.1 RuntimeException RuntimeException體系包括錯誤的類型轉換、數組越界訪問和試圖訪問null 指標等等。處理RuntimeException的原則是:如果出現RuntimeException,那麼一定是程式員的錯誤。例如,可以通過檢查數組下標和數組邊界來避免數組越界訪問異常。

2.2.2.2 其他(IOException等等)這類異常一般是外部錯誤,例如試圖從檔案尾後讀取資料等,這並不是程式本身的錯誤,而是在應用環境中出現的外部錯誤。
2.3 與C++異常分類的不同
2.3.1 其實,Java中RuntimeException這個類名起的並不恰當,因為任何異常都是運行時出現的。(在編譯時間出現的錯誤並不是異常,換句話說,異常就是為瞭解決程式運行時出現的的錯誤)。

2.3.2 C++中logic_error與Java中的RuntimeException是等價的,而runtime_error與Java中非RuntimeException類型的異常是等價的。

3 異常的使用方法
3.1 聲明方法拋出異常
3.1.1 文法:throws(略)
3.1.2 為什麼要聲明方法拋出異常?方法是否拋出異常與方法傳回值的類型一樣重要。假設方法拋出異常確沒有聲明該方法將拋出異常,那麼客戶程式員可以調用這個方法而且不用編寫處理異常的代碼。那麼,一旦出現異常,那麼這個異常就沒有合適的異常控制器來解決。

3.1.3 為什麼拋出的異常一定是已檢查異常? RuntimeException與Error可以在任何代碼中產生,它們不需要由程式員顯示的拋出,一旦出現錯誤,那麼相應的異常會被自動拋出。而已檢查異常是由程式員拋出的,這分為兩種情況:客戶程式員調用會拋出異常的庫函數(庫函數的異常由庫程式員拋出);客戶程式員自己使用throw語句拋出異常。遇到Error,程式員一般是無能為力的;遇到RuntimeException,那麼一定是程式存在邏輯錯誤,要對程式進行修改(相當於調試的一種方法);只有已檢查異常才是程式員所關心的,程式應該且僅應該拋出或處理已檢查異常。

3.1.4 注意:覆蓋父類某方法的子類方法不能拋出比父類方法更多的異常,所以,有時設計父類的方法時會聲明拋出異常,但實際的實現方法的代碼卻並不拋出異常,這樣做的目的就是為了方便子類方法覆蓋父類方法時可以拋出異常。

3.2 如何拋出異常
3.2.1 文法:throw(略)
3.2.2 拋出什麼異常?對於一個異常對象,真正有用的資訊時異常的物件類型,而異常對象本身毫無意義。比如一個異常對象的類型是ClassCastException,那麼這個類名就是唯一有用的資訊。所以,在選擇拋出什麼異常時,最關鍵的就是選擇異常的類名能夠明確說明異常情況的類。

3.2.3 異常對象通常有兩種建構函式:一種是無參數的建構函式;另一種是帶一個字串的建構函式,這個字串將作為這個異常對象除了類型名以外的額外說明。
3.2.4 建立自己的異常:當Java內建的異常都不能明確的說明異常情況的時候,需要建立自己的異常。需要注意的是,唯一有用的就是類型名這個資訊,所以不要在異常類的設計上花費精力。

3.3 捕獲異常如果一個異常沒有被處理,那麼,對於一個非圖形介面的程式而言,該程式會被中止並輸出異常資訊;對於一個圖形介面程式,也會輸出異常的資訊,但是程式並不中止,而是返回使用者介面處理迴圈中。

3.3.1 文法:try、catch和finally(略)控制器模組必須緊接在try塊後面。若擲出一個異常,異常控制機制會搜尋參數與異常類型相符的第一個控制器隨後它會進入那個catch 從句,並認為異常已得到控制。一旦catch 從句結束對控制器的搜尋也會停止。 3.3.1.1 捕獲多個異常(注意文法與捕獲的順序)(略)

3.3.1.2 finally的用法與異常處理流程(略)
3.3.2 異常處理做什嗎?對於Java來說,由於有了垃圾收集,所以異常處理並不需要回收記憶體。但是依然有一些資源需要程式員來收集,比如檔案、網路連接和圖片等資源。

3.3.3 應該聲明方法拋出異常還是在方法中捕獲異常?原則:捕捉並處理哪些知道如何處理的異常,而傳遞哪些不知道如何處理的異常
3.3.4 再次拋出異常
3.3.4.1 為什麼要再次拋出異常?在本級中,只能處理一部分內容,有些處理需要在更高一級的環境中完成,所以應該再次拋出異常。這樣可以使每級的異常處理器處理它能夠處理的異常。

3.3.4.2 異常處理流程對應與同一try塊的catch塊將被忽略,拋出的異常將進入更高的一級。
4 關於異常的其他問題
4.1 過度使用異常首先,使用異常很方便,所以程式員一般不再願意編寫處理錯誤的代碼,而僅僅是簡簡單單的拋出一個異常。這樣做是不對的,對於完全已知的錯誤,應該編寫處理這種錯誤的代碼,增加程式的魯棒性。另外,異常機制的效率很差。

4.2 將異常與普通錯誤區分開對於普通的完全一致的錯誤,應該編寫處理這種錯誤的代碼,增加程式的魯棒性。只有外部的不能確定和預知的執行階段錯誤才需要使用異常。
4.3 異常對象中包含的資訊一般情況下,異常對象唯一有用的資訊就是類型資訊。但使用異常帶字串的建構函式時,這個字串還可以作為額外的資訊。調用異常對象的getMessage()、toString()或者printStackTrace()方法可以分別得到異常對象的額外資訊、類名和呼叫堆疊的資訊。並且後一種包含的資訊是前一種的超集。

常用異常:

  UnsupportedOperationException不支援的操作

  IllegalArgumentException非法參數

  IndexOutOfBoundsException索引出界

  IllegalStateException非法狀態
異常跟普通的警告等有一定的區別。當應用程式發生異常時,會中斷正在執行的程式的正常指令流。也就是說,發生異常後面的代碼將得不到正確的執行。甚至還會觸發資料庫的後援動作。

    在Java開發平台中,異常包括預定義異常與自訂異常。這兩種異常的類型互為補充。作為一個合格的程式開發人員,要善於在應用程式中使用異常。這可以提高應用程式的互動性。同時,也是保證應用程式正常啟動並執行前提。故異常的處理對於開發一個優秀的應用程式來說非常的重要。為此筆者認為程式開發人員應該對Java應用程式的常見異常有一個深入的瞭解。只有在瞭解這些常見異常的情況下,才能夠做好自訂異常的處理。

    一、常見異常的類型與原因。

    對於Java應用程式的常見異常,筆者認為程式開發人員要從兩個方面去瞭解。一是要知道有哪些常見的Java應用程式異常,二是需要知道哪些原因可能會造成這個異常。這不僅需要程式管理員在日常工作中要注意積累,在必要的情況下還需要去從其它渠道收集資料。筆者對此就進行一個分析,希望能夠對各位程式開發人員有一定的協助。

    1、 SQLException:操作資料庫異常類。

    現在的Java應用程式大部分都是依賴於資料庫啟動並執行。當Java應用程式與資料庫進行溝通時如果產生了錯誤,就會觸發這個類。同時會將資料庫的錯誤資訊通過這個類顯示給使用者。也就是說,這個操作資料庫異常類是資料庫與使用者之間異常資訊傳遞的橋樑。如現在使用者往系統中插入資料,而在資料庫中規定某個欄位必須唯一。當使用者插入資料的時候,如果這個欄位的值跟現有的紀錄重複了,違反了資料庫的唯一性限制式,此時資料庫就會跑出一個異常資訊。這個資訊一般使用者可能看不到,因為其發生在資料庫層面的。此時這個操作資料庫異常類就會捕捉到資料庫的這個異常資訊,並將這個異常資訊傳遞到前台。如此的話,前台使用者就可以根據這個異常資訊來分析發生錯誤的原因。這就是這個操作資料庫異常類的主要用途。在Java應用程式中,所有資料庫操作發生異常時,都會觸發這一個類。所有此時Java應用程式本身的提示資訊往往過於籠統,只是說與資料庫互動出現錯誤,沒有多大的參考價值。此時反而是資料庫的提示資訊更加有使用價值。

    2、 ClassCastException:資料類型轉換異常。

    在Java應用程式中,有時候需要對資料類型進行轉換。這個轉換包括顯示的轉換與隱式的轉換。不過無論怎麼轉換,都必須要符合一個前提的條件,即資料類型的相容性。如果在資料轉換的過程中,違反了這個原則,那麼就會觸發資料類型轉換異常。如現在在應用程式中,開發人員需要將一個字元型的日期資料轉換為資料庫所能夠接受的日期型資料,此時只需要在前台應用程式中進行控制,一般不會有問題。但是,如果前台應用程式缺乏相關的控制,如使用者在輸入日期的時候只輸入月、日資訊,而沒有年份的資訊。此時應用程式在進行資料類型轉換的時候,就會出現異常。根據筆者的經驗,資料類型轉換異常在應用程式開發中使一個出現的比較多的異常,也是一個比較低級的異常。因為大部分情況下,都可以在應用程式視窗中對資料類型進行一些強制的控制。即在資料類型進行轉換之前,就保證資料類型的相容性。如此的話,就不容易造成資料類型的轉換異常。如在只允許數實值型別的欄位中,可以設定不允許使用者輸入數值以外的字元。雖然說有了異常處理機制,可以保證應用程式不會被錯誤的運行。但是在實際開發中,還是要儘可能多的預見錯誤發生的原因,盡量避免異常的發生。

    3、 NumberFormatException:字串轉換為數字類型時拋出的異常。

    在資料類型轉換過程中,如果是字元型轉換為數字型過程中出現的問題,對於這個異常在Java程式中採用了一個獨立的異常,即NumberFormatException.如現在講字元型的資料“123456”轉換為數值型資料時,是允許的。但是如果字元型資料中包含了非數字型的字元,如123#56,此時轉換為數值型時就會出現異常。系統就會捕捉到這個異常,並進行處理。

Java應用程式中常見的異常類還有很多。如未找到相應類異常、不允許訪問某些類異常、檔案已經結束異常、檔案未找到異常、欄位未找到異常等等。一般系統開發人員都可以根據這個異常名來判斷當前異常的類型。雖然不錯,但是好記性不如爛筆頭。程式開發人員在必要的時候(特別是存在自訂異常的時候),最後手頭有一份異常明細表。如此的話,無論是應用程式在調試過程中發現問題,還是運行過程中接到使用者的投訴,都可以及時的根據異常名字來找到異常發生的原因。從而可以在最短時間內解決異常,恢複應用程式的正常運行。這個措施筆者用了很多年,非常的有效。

    二、異常管理的實用建議。

    對於操作資料庫異常來說,Java應用程式只提供了一個異常類。故光憑Java應用程式的錯誤資訊,往往不能夠輔助應用程式人員排除錯誤的原因。只能夠指名是應用程式錯誤還是資料庫錯誤導致的這個異常。為了更進一步指明問題的原因,在資料庫層面定義異常的時候,最好能夠說明具體的原因。如前台應用程式可能會調用資料庫的函數或者過程。此時在資料庫的函數或者過程中做好能夠說明某個異常的具體原因。如根據某個基礎資料表產生另一張表的時候,某個欄位不能夠為空白等等。將這些異常資訊說明清楚後,如果真的遇到類似的異常時,操作資料庫異常類就會將資料庫的異常資訊反會給前台使用者。從而有利於使用者尋找問題的原因,並在最短時間內改正。當然,這需要Java程式員與資料庫設計人員進行協調。

    其次需要注意的是,異常並不是常態。也就是說,大部分異常可以通過前提的合理預見與預防,來消除。如設計到四則運算,可以在前台應用程式視窗中限制在除數欄位內輸入0值等手段來消除應用程式運行中可能產生的異常。不過這往往要求應用程式開發人員有比較豐富的工作經驗以及由比較嚴密的思維邏輯。雖然這有一定的難度,但是筆者認為程式開發人員還是應該往這方面努力,而不要老是讓使用者作為你的實驗品,讓使用者來發現應用程式中的設計Bug.筆者認為,只有一些實在是程式人員無法控制的因素才允許拋出異常。如果應用程式開發人員能夠意識到這種錯誤、但是仍然沒有引起重視或者採取有效措施防止出現這種異常,那麼筆者是不允許的。

ArithmeticException(除數為0的異常), BufferOverflowException(緩衝區上溢異常), BufferUnderflowException(緩衝區下溢異常), IndexOutOfBoundsException(出界異常), NullPointerException(null 指標異常), EmptyStackException(空棧異常), IllegalArgumentException(不合法的參數異常), NegativeArraySizeException, NoSuchElementException,
SecurityException, SystemException, UndeclaredThrowableException

1. java.lang.NullPointerException
  異常的解釋是"程式遇上了null 指標",簡單地說就是調用了未經初始化的對象或者是不存在的對象,即把數組的初始化和數組元素的初始化混淆起來了。數組的初始化是對數組分配需要的空間,而初始化後的數組,其中的元素並沒有執行個體化,依然是空的,所以還需要對每個元素都進行初始化(如果要調用的話)
  2. java.lang.ClassNotFoundException  異常的解釋是"指定的類不存在"。
  3. java.lang.ArithmeticException  這個異常的解釋是"數學運算異常",比如程式中出現了除以零這樣的運算就會出這樣的異常。
  4. java.lang.ArrayIndexOutOfBoundsException
  異常的解釋是"數組下標越界",現在程式中大多都有對數組的操作,因此在調用數組的時候一定要認真檢查,看自己調用的下標是不是超出了數組的範圍,一般來說,顯示(即直接用常數當下標)調用不太容易出這樣的錯,但隱式(即用變數表示下標)調用就經常出錯了,還有一種情況,是程式中定義的數組的長度是通過某些特定方法決定的,不是事先聲明的,這個時候,最好先查看一下數組的length,以免出現這個異常。
  5. java.lang.IllegalArgumentException
  這個異常的解釋是"方法的參數錯誤",比如g.setColor(int red,int green,int blue)這個方法中的三個值,如果有超過255的也會出現這個異常,因此一旦發現這個異常,我們要做的,就是趕緊去檢查一下方法調用中的參數傳遞是不是出現了錯誤。
  6. java.lang.IllegalAccessException
  這個異常的解釋是"沒有存取權限",當應用程式要調用一個類,但當前的方法即沒有對該類的存取權限便會出現這個異常。對程式中用了Package的情況下要注意這個異常

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.