java異常分為兩大類,Checked異常和Runtime異常,Checked異常都是在編譯階段可以被處理的異常。
Checked異常和Runtime異常的區別和聯系
常見異常類
列舉幾個常見的運行時異常RuntimeException:
列舉幾個非運行時異常(Checked異常):
Error錯誤
Error錯誤一般指與虛擬機相關的問題,如系統崩潰,虛擬機錯誤,動態鏈接失敗等,這種錯誤無法恢復或不可被捕獲,將導致應用程序中斷。通常應用程序也無法處理這些錯誤,因此程序中不應該試圖使用catch來捕獲Error對象。在方法定義時,也無需throws Error對象。
Checked異常的使用
前面提到了Checked必須顯式的處理,不然編譯報錯,比如聲明一個文件輸入流:
FileInputStream fis = new FileInputStream("test.md");
這段代碼編譯會報錯
Unhandled exception type FileNotFoundException
因此必須顯式的處理它,處理Checked異常的方式一般有兩種:
如果知道如何處理,那么最好使用try…catch...塊處理:
//Checked異常必須被顯式處理try { FileInputStream fis = new FileInputStream("test.md");} catch (FileNotFoundException e) { e.printStackTrace(); System.out.println("文件不存在!");}
如果不知道如何處理,那么就在方法中拋出,由上一級調用者處理:
public static void main(String[] args) throws FileNotFoundException { //Checked異常必須被顯式處理 //在main方法中拋出異常,交給JVM處理,JVM對異常的處理辦法就是打印跟蹤棧信息,并終止程序運行 FileInputStream fis = new FileInputStream("test.md");}
使用throw自行拋出異常
有的時候根據業務需要,我們在程序里面會自行拋出異常,比如如果讀取的文件內容為空,我們就認為這是一個異常,這時候我們可以使用throw來主動拋出異常,并且用catch捕獲它:
//使用throw主動拋出異常try { FileInputStream fis = new FileInputStream("test.md"); if(fis.read() == 0) { throw new IOException("空文件"); }} catch (IOException e) { e.printStackTrace();}
如果throw拋出的是一個runtime異常,那么程序可以用try…catch…捕獲,也可以不用理會。
異常鏈處理
在真實的企業級應用中,我們往往不會講底層的異常暴露給上層應用,比如不會把SQL異常暴露到用戶界面上。一是對于用戶而言,看到SQL異常對他們也沒啥幫助,二是對于惡意用戶而言,暴露底層異常不安全。
那么如何屏蔽底層異常呢?通常的做法是:程序先捕獲原始異常,然后拋出一個新的業務異常,新的業務異常包含了對用戶的提示信息,這種處理方式成為異常轉譯。下面演示一個創建用戶的程序如何屏蔽底層異常:
//演示異常鏈,創建用戶public void createSubscriber(int subId) throws BusinessException { try { //創建用戶的邏輯...... }catch(Exception e){ //處理并保存原始異常... //拋出新的業務異常 throw new BusinessException("用戶創建失敗"); }}
可以看到程序把原始異常隱藏起來,僅向上提供必要的異常提示信息,可以保證底層異常不會擴展到表現層,這完全符合對象的封裝原則。
這種把捕獲一個異常然后拋出另一個異常,并把原始異常信息保存下來,是一種典型的鏈式處理,在設計模式中被稱為責任鏈模式。
使用異常的幾個建議
我們使用異常是為了實現幾個目標:
針對這些目標,我們應該做到:
1、不要過度使用和依賴它:異常很方便,但是不要把正常的邏輯處理都使用異常處理,比如
//原始代碼if(fileSize > 100){ Sysotem.out.println("文件過大,請重新上傳"); continue;}//改成使用異常 if(fileSize > 100){ throw new Exception("文件過大,請重新上傳");}//這樣做,很明顯不負責任。
新聞熱點
疑難解答
圖片精選