異常概述
- 依賴于try catch finally throw throws五個關鍵字
- Java把一場分為兩種:Checked Runtime滥酥,Checked異嘲枚桑可以在編譯階段被發(fā)現蝗肪,所以強制程序處理所有的Checked異常斜友,Runtime異常無需處理
- 無法窮舉所有的異常情況词顾,錯誤處理代碼和業(yè)務實現代碼混雜八秃,影響可讀性,增加維護難度计技,使用Java異常處理機制就可以解決這個問題
- Java把錯誤分為Exception和Error喜德,Error一般指與虛擬機相關的問題,通常程序無法處理這些錯誤垮媒,所以不應該使用catch捕捉Error對象
異常處理機制
使用try...catch捕獲異常
try
{
//業(yè)務實現代碼
}
catch (Excption e)
{
//處理異常
}
當try中業(yè)務邏輯代碼出現異常時舍悯,系統(tǒng)會自動生成一個異常對象交給Java運行時環(huán)境航棱,拋出(throw)異常
拋出異常后,Java運行時環(huán)境收到異常對象時尋找對應的catch塊交給其處理萌衬,如果找不到捕獲異常的catch塊饮醇,則運行時環(huán)境種植,程序退出
會依次判斷該異常對象是否為catch塊后異常類或其子類的實例秕豫,如果是則交由其處理
try塊后的花括號不能省略朴艰,catch也不能省略
catch應該先處理小異常再處理大異常,把父類異常的catch塊排在子類的后面混移,否則會出現編譯錯誤
Java7提供多異常捕獲祠墅,一個catch可以捕獲多種類型的異常,用|隔開歌径,捕獲多種類型的異常時毁嗦,異常變量有隱式的final修飾,程序不能對其重新賦值
catch (...|...|... e){}
異常對象包含的訪問信息的方法:getMessage printStackTrace getStackTrance
finally回收資源
- try塊內打開的物理資源(數據庫連接回铛、網絡連接狗准、磁盤文件等),這些物理資源必須顯式回收
try{}
catch(.. e){}
catch(.. e){}
...
finally
{
//回收資源
}
- 只有try塊時必須的茵肃,catch和finally至少出現其中之一腔长,finally位于catch之后,catch位于try之后
- 除非再try或catch中調用了退出虛擬機的方法System.exit(1);验残,不管怎么樣finally塊總會被執(zhí)行
- 通常不要在finally塊中使用return或throw方法終止語句捞附,會導致try catch中的return throw語句失效
- 層次太深的潛逃異常處理沒有太大的必要,會導致程序可讀性降低
- Java7自動給關閉資源的try語句胚膊,資源的實現類必須實現AutoCloseable或Closeable(AutoCloseable子接口故俐,只能拋出IOException或其子類)接口,也就是實現了close()方法
try(//聲明初始可關閉的資源){}
- 自動關閉資源的try語句相當于包含了隱式的finally塊紊婉,所以這個try可以既沒有catch塊也沒有finally塊
Checked和Runtime異常體系
- 不是RuntimeException類及其子類的異常實例稱為Checked異常
- 對于Checked異常的處理方式
- 當明確知道如何處理時使用try...catch捕獲修復該異常
- 當前方法不知道如何處理時應該在定義該方法時拋出該異常
- Runtime異常無需顯式聲明拋出药版,如果需要捕獲,也可以使用try...catch
- throws聲明拋出異常喻犁,
throws EC1,EC2...
public static void main(String[] args) throws IOException {}
- 當前方法不知如何處理該異常槽片,則拋出有上一級調用者處理,如果main方法也不知道肢础,也可以使用throws拋出交給JVM處理还栓。
- JVM處理異常:打印異常跟蹤棧信息,終止程序運行传轰。
- 重寫使用throws聲明拋出異常的方法時剩盒,子類方法聲明拋出的異常類型應該時父類的相同類或子類,并且子類方法聲明拋出的異常不能比父類聲明的多
throw拋出異常
- Java允許自行拋出異常慨蛙,使用throw語句
throw ExceptionInstance;
- 如果拋出Checked異常辽聊,需要處于try塊或有throws聲明拋出的方法中纪挎,如果是Runtime異常,則不需要跟匆,自行拋出Runtime異常比Checked異常靈活
自定義異常類
- 需要繼承Exception基類异袄,如果自定義Runtime異常則可以繼承RuntimeException基類
- 通常需要兩個構造器,一個無參玛臂,一個字符串參數(描述異常對象的信息)烤蜕,getMessage()返回值
public myException(String msg){super(msg);}
catch和throw同時使用
- 在出現異常的方法內捕獲并處理異常,該方法的調用者將不能再次捕獲該異常
- 方法簽名中聲明拋出該異常迹冤,改異常將完全交給方法的調用者處理
- 在實際應用中讽营,完全處理一個異常必須由幾方法寫作才可以,比如在出現異常的方法中捕獲并處理部分叁巨,還需要再次拋出斑匪,讓調用者也捕獲到異常處理剩下的部分
- 在catch塊中結合throw語句完成
catch (Exception e)
{
e.printStackTrace();//在本方法中只是進行一個打印異常信息的操作
throw new AuctionException("想傳遞的信息");//再次拋出自定義異常
}
- 企業(yè)級應用對異常處理通常分為兩部分
- 應用后臺需要通過日志記錄異常發(fā)生的詳細情況
- 向應用的使用者傳達提示
- Java7增強的throw語句,編譯器會檢查throw語句拋出異常的實際類型锋勺,而不是僅根據catch后的類型判斷,因此方法聲明中只需要聲明拋出實際類型的異常即可
異常鏈
- 不應該把底層的異常傳到用戶界面狡蝶,對于用戶庶橱,此舉沒有任何幫助,且對于惡意用戶贪惹,暴露異常是不安全的
- 應該把底層原始異常捕獲苏章,拋出一個新的業(yè)務異常,這種處理方式叫做異常轉譯奏瞬,完全符合面向對象的封裝原則
- 捕獲一個異常接著拋出另一個異常枫绅,并把原始已異常信息保存下來是一種典型的鏈式處理,職責鏈模式硼端,也稱為異常鏈
- Java1.4后Throwable的子類在構造器中可以接受一個cause對象作為參數并淋,表示原始異常,這樣可以通過異常鏈追蹤到異常最初發(fā)生的位置珍昨,獲取原始異常信息
異常跟蹤棧
- 只要異常沒有被完全捕獲县耽,從發(fā)生異常的方法逐漸向外傳播,打印異常的跟蹤棧信息
- printStackTrace()方法用于調試镣典,最終還是應該避免使用它兔毙,應該對捕獲的異常進行處理,而不是簡單的打印
異常處理規(guī)則
- 成功處理異常的四個目標
- 是程序代碼混亂最小化
- 捕獲并保留診斷信息
- 通知合適的人員
- 采用合適的方式結束異承执海活動
- 異常只應該用于處理非正常的情況澎剥,不要去代替正常的流程控制
- 不要使用過于龐大的try塊,應該分割成單獨的try塊赶舆,分別捕獲并處理異常
- 避免使用Catch All語句哑姚,catch(Throwable t){...}
- 不要忽略捕獲到的異常趾唱,去處理異常,重新拋出新異常蜻懦,再在合適的層處理異常