在《java程式設計思想》中這樣定義異常:阻止目前方法或作用域繼續執行的問題。異常是java程式設計中不可分割的一部分,如果不了解如何使用它們,那麼我們隻能完成很有限的工作。
異常分為3種:
error - 描述了java運作系統中的内部錯誤以及資源耗盡的情況。應用程式不應該抛出這種類型的對象。如果這種内部錯誤出現,除了通知使用者錯誤發生以及盡力安全的退出程式外,在其他方面是無能為力的。
編譯時異常 exception - 它指出了合理的應用程式想要捕獲的條件。exception又分為兩類:ioexception和runtimeexception。由程式設計導緻的錯誤,會導緻runtimeexception異常。而其他錯誤原因導緻的異常(例如因為i/o錯誤導緻曾經運作正确的程式出錯),都不會導緻runtimeexception異常。
運作時 runtimeexception - 表示運作時異常,不強制要求寫出顯示的捕獲代碼,但如果沒有被捕獲到,則線程會被強制中斷
繼承關系:
從 runtimeexception 衍生出來的異常包括下面的問題:
錯誤的類型轉換
數組越界通路
試圖通路空指針
從 ioexception 衍生出來的異常包括:
試圖從檔案尾後面讀取資料
試圖打開一個錯誤可是的 url
試圖用一個字元串來構造一個 class 對象,而與該字元串對應的類并不存在
異常的好處:
1、将問題進行封裝
2、将正常流程代碼和問題代碼相分離,便于閱讀。
在java應用程式中,異常處理機制為:抛出異常,捕捉異常。
<code>抛出異常</code>:當一個方法出現錯誤引發異常時,方法建立異常對象并傳遞運作時系統,異常對象中包含了異常類型和異常出現時的程式狀态等異常資訊。運作時系統負責尋找處置異常的代碼并執行。
<code>捕獲異常</code>:在方法抛出異常之後,運作時系統将轉為尋找合适的異常處理器(exception handler)。潛在的異常處理器是異常發生時依次存留在調用棧中的方法的集合。當異常處理器所能處理的異常類型與方法抛出的異常類型相符時,即為合适的異常處理器。運作時系統從發生異常的方法開始,依次回查調用棧中的方法,直至找到含有合适異常處理器的方法并執行。當運作時系統周遊調用棧而未找到合适的異常處理器,則運作時系統終止。同時,意味着java程式的終止。
任何 java 代碼都可以抛出異常,如:自己編寫的代碼、來自 java 開發環境包中代碼,或者 java 運作時系統。無論是誰,都可以通過 java 的 throw 語句抛出異常。
從方法中抛出的任何異常都必須使用 <code>throws</code> 子句。
捕捉異常通過 <code>try-catch</code> 語句或者 <code>try-catch-finally</code> 語句實作。
編譯時異常exception,給了幾條禁止的原則,他們是:
1)不要直接忽略異常;
2)不要用try-catch包住過多語句;
3)不要用異常處理來處理程式的正常控制流;
4)不要随便将異常迎函數棧向上傳遞,能處理盡量處理。
向上傳播異常:
如果不能用上述恢複措施,就檢查能不能向上傳播,什麼情況下可以向上傳播呢?有多種說法,一種說法是當本方法恢複不了時,這個說法顯然是錯誤,因為上層也不一定能恢複。另外還有兩種說法是:1.當上層邏輯可以恢複程式時;2.當本方法除了列印之外不能做任何處理,而且不确定上層能否處理。這種兩種說法都是正确的,但還不夠,因為也有的情況,明确知道上層恢複不了也需要上層處理,是以我認為正确的做法是:當你認為本異常應該由上層處理時,才向上傳播。
何時選用編譯時異常:
1、如果調用者可以恢複此異常情況
2、如果調用者不能恢複,但能做出有意義的事,如轉譯等。如果你不确定調用者能否做出有意義的事,就别使編譯時異常,免得被抱怨。
3、應盡最大可能使用編譯時異常來代替錯誤碼,這條也是編譯時異常設計的目的。
另外,必須注意使用編譯時異常的目的是為了恢複執行,是以設計異常類的時候,應提供盡量多的異常資料,以便于上層恢複,比如一個解析錯誤,可以在設計的異常類寫幾個變量來存儲異常資料:解析出錯的句子的内容,解析出錯句子的行号,解析出錯的字元在行中的位置。這些資訊可能幫助調用恢複程式。
當使用多個 catch 語句塊來捕獲異常時,需要将父類的 catch 語句塊放到子類型的 catch 塊之後,這樣才能保證後續的 catch 可能被執行,否則子類型的 catch 将永遠無法到達,java 編譯器會報編譯錯誤。
如果 try 語句塊中存在 return 語句,那麼首先會執行 finally 語句塊中的代碼,然後才傳回。
如果 try 語句塊中存在 <code>system.exit(0)</code> 語句,那麼久不會執行 finally 語句塊的代碼了,因為 <code>system.exit(0)</code>會終止目前運作的 jvm。程式在 jvm 終止前結束執行。
1、error和exception有什麼差別
error 表示系統級的錯誤,是java運作環境内部錯誤或者硬體問題,不能指望程式來處理這樣的問題,除了退出運作外别無選擇,它是java虛拟機抛出的。
exception 表示程式需要捕捉、需要處理的異常,是由與程式設計的不完善而出現的問題,程式必須處理的問題
2、運作時異常和一般異常有何不同
java 提供了兩類主要的異常:runtimeexception 和 checkedexception
一般異常(checkedexception)主要是指 io 異常、sql 異常等。對于這種異常,jvm 要求我們必須對其進行 cathc 處理,是以,面對這種異常,不管我們是否願意,都是要 寫一大堆的 catch 塊去處理可能出現的異常。
運作時異常(runtimeexception)我們一般不處理,當出現這類異常的時候程式會由虛拟機接管。比如,我們從來沒有去處理過 nullpointerexception,而且這個異常還是最 常見的異常之一。
出現運作時異常的時候,程式會将異常一直向上抛,一直抛到遇到處理代碼,如果沒有 catch 塊進行處理,到了最上層,如果是多線程就有 thread.run()抛出,如果不是多線程 那麼就由 <code>main.run()</code> 抛出。抛出之後,如果是線程,那麼該線程也就終止了,如果是主程式,那麼該程式也就終止了。
其實運作時異常的也是繼承自 exception,也可以用 catch 塊對其處理,隻是我們一般不處理罷了,也就是說,如果不對運作時異常進行 catch 處理,那麼結果不是線程退出就是 主程式終止。
如果不想終止,那麼我們就必須捕獲所有可能出現的運作時異常。如果程式中出現了異常資料,但是它不影響下面的程式執行,那麼我們就該在catch塊裡面将異常資料舍棄, 然後記錄日志。如果,它影響到了下面的程式運作,那麼還是程式退出比較好些。
3、java 中異常處理機制的原理
jav a通過面向對象的方式對異常進行處理,java 把異常按照不同的類型進行分類,并提供了良好的接口。在 java 中,每個異常都是一個對象,它都是 throwable 或其子類的執行個體。當一個方法出現異常後就會抛出一個異常對象,該對象中包含有異常資訊,調用這個對象的方法可以捕獲到這個異常并對異常進行處理。java 的異常處理是通過5個 關鍵詞來實作的:try、catch、throw、throws、finally。
<code>try</code>:用來指定一塊預防所有異常的程式
<code>catch</code>:緊跟在try後面,用來捕獲異常
<code>throw</code>:用來明确的抛出一個異常
<code>throws</code>:用來标明一個成員函數可能抛出的各種異常
<code>finally</code>:確定一段代碼無論發生什麼異常都會被執行的一段代碼。
4、你平時在項目中是怎樣對異常進行處理的。
1)盡量避免出現 runtimeexception。例如對于可能出現空指針的代碼,帶使用對象之前一定要判斷一下該對象是否為空,必要的時候對 runtimeexception也進行 <code>try catch</code> 處理。
2)進行 <code>try catch</code> 處理的時候要在 catch 代碼塊中對異常資訊進行記錄,通過調用異常類的相關方法擷取到異常的相關資訊。
5、final、finally、finalize的差別
(1)、final 用于聲明變量、方法和類的,分别表示變量值不可變,方法不可覆寫,類不可以繼承
(2)、finally 是異常進行中的一個關鍵字,表示 <code>finally{}</code> 裡面的代碼一定要執行
(3)、finalize 是 object 類的一個方法,在垃圾回收的時候會調用被回收對象的此方法。