當出現程序無法控制的外部環境(文件不存在,文件內容損壞,網絡不可用等)問題時,java就會用異常對象來描述。
Java中用2種方法處理異常:
1、 在發生異常的地方直接處理。
2、 將異常拋給調用者,讓調用者處理。
異常的分類:
1、 檢查性異常:java.lang.Exception 程序正確,但因為外在的環境條件不足引發
2、 運行期異常:java.lang.RuntimeException 這意味着程序出現bug,如數組越界,除以0等,這類異常需要更改程序來避免
3、 錯誤:java.lang.Error 可能源於程序的bug,但更可能源於環境問題,如內存耗盡、系統崩潰、動態鏈接失敗等,這種錯誤無法恢復或不可能捕獲,會導致程序中斷,錯誤在程序中無序處理,而由運行環境處理。
注意:進行異常捕獲時所有父類異常的catch塊都應該排在子類異常catch塊的后面(先處理小異常,再處理大異常)。
訪問異常信息:如果程序需要在catch塊中訪問對象的相關信息,可以通過調用catch后異常形參的方法來獲取
1、 getMessage():返回異常的詳細描述字符串。
2、 printStackTrace():將異常的跟蹤棧信息輸出到標准錯誤輸出。
3、 printStackTrace(PrintStream s):將該異常的跟蹤棧信息輸出到指定輸出流。
4、 getStackTrace():返回該異常的跟蹤棧信息。
利用finally回收資源:
程序在try里打開了一些物理資源(如數據庫連接、網絡連接等),這些物理資源必須顯示回收。因為java的垃圾回收機制不會回收任何物理資源,只能回收堆內存中對象所占用的內存。為了保證一定能回收try中打開的物理資源,異常處理機制提供了finally塊,不管是否出現異常,finally塊總會被執行。異常處理語法結構:只有try塊是必須的,catch和finally是可選的,但至少出現其中之一,catch可有多個。
以下情形,finally將不會被執行
1、 finally塊中發生異常
2、 程序所在線程死亡
3、 在前面的代碼中用了System.exit()
4、 關閉cpu
注意:一旦finally中使用了return或throw語句,將會導致try塊、catch塊中的return、throw語句失效。
(當java程序執行try塊、catch塊時遇到了return或throw語句,這兩個語句會導致方法立即結束,所以系統並不會立即執行者兩個語句,而是去尋找是否有finally塊,如果沒有,程序立即執行return或throw語句,方法終止;如果有finally,系統立即執行finall塊,只有當finally塊執行完成后系統才跳回來執行try、Catch塊里的return、throw,如果finally里也使用了return或throw等導致方法終止的語句,則finally塊已經終止了方法,系統將不會跳回執行try、catch塊里的任何代碼。)
使用throws聲明拋出異常:throws只能在方法簽名中使用,可以聲明拋出多個異常類,以逗號隔開。
使用throws的情況:
1、當前方法不知道應該如何處理這種類型的異常。
2、該異常應該由上一級調用者處理。
拋出的異常將講給JVM處理。處理方法是:打印異常跟蹤棧信息並終止程序運行,這就是程序一道異常后自動結束的原因。
注意:使用throws拋出異常時有一個限制,就是方法重寫時:子類方法中聲明拋出的異常類型應該是父類拋出異常類型的子類或相等。
使用Checked異常至少存在兩大不便之處:
1、對於程序中Checked異常,java要求必須顯式的捕獲並處理該異常或顯式聲明拋出,這就愛增加了編程的復雜度。
2、如果在方法中顯式聲明拋出Checked異常麻將會導致方法簽名與異常耦合,如果方法是重寫父類的方法,則該方法能拋出的異常還受被重寫方法所拋出的異常限制。
使用throw拋出異常:
java允許程序自行拋出異常,由throw來完成。其拋出的不是異常類,而是一個異常實例,每次只能拋出一個異常實例。
如果throw拋出的異常時checked異常,則該throw語句要么處於try塊里,顯式捕獲該異常,要么放在一個帶有throws聲明的方法中;如果throw語句拋出的異常時runtime異常,則該語句無須放在try塊里或帶throws拋出的方法中,程序可以顯式使用try...catch來捕獲,並處理異常,也可以完全不理會該異常,把該異常交給該方法調用者處理。
自定義異常類:需要繼承Exception基類,如希望自定義Runtime異常則需繼承RuntimeException基類,定義異常時要提供兩種構造器,無參的和帶一個字符串的,這字符串作為該異常對象的詳細說明,即getMessaga方法的返回值。
總結:
1、處理異常,對異常采用合適的修補,然后繞過異常發生的地方繼續執行;或者用別的數據進行計算以代替期望的方法返回值;或者提示用戶重新操作等,總之,對於checked異常,程序應該盡量采用修復。
2、重新拋出異常,把當前運行環境下能做的事情盡量做完,然后進行異常轉譯,把異常包裝成當前層的異常,重新拋出給上層調用者。
3、在合適的層處理異常。如果當前層不清楚如何處理異常,就不要在當前層使用catch來捕獲異常,直接使用throws拋出異常,讓上層調用者來負責處理異常。