15.1 異常處理機制
? ??? ??使用try...catch捕獲異常:如果執(zhí)行try塊里的業(yè)務邏輯代碼出現(xiàn)異常,則系統(tǒng)自動創(chuàng)建一個異常對象,該異常會被提交給Java運行時環(huán)境,這個過程被稱為拋出(throw)異常。當Java運行時環(huán)境收到異常時,會尋找能處理該異常對象的catch塊,如果找到合適的catch塊,就把這個異常交給catch塊處理,這個過程被稱為捕獲(catch)異常;如果Java運行時環(huán)境找不到捕獲異常的catch塊,則運行時環(huán)境終止,Java程序也將退出。
? ? ? ? 異常類的繼承體系:Java把所有的非正常情況稱為兩種,異常Exception和錯誤Error,都繼承了Throwable父類。Error錯誤無法恢復和捕獲,將導致應用程序中斷。
? ? ? ? Java7提供的多異常捕獲:捕獲多種類型的異常時,多種異常類型之間使用豎線|隔開;異常變量有隱式的final修飾,因此程序不能對異常變量重新賦值。
? ??? ??訪問異常信息的方法(通過catch塊的后異常形參進行調(diào)用):
? ? ? ? - getMessage():返回該異常的詳細描述字符串。
? ? ? ? - printStackTrace():將該異常的跟蹤棧信息輸出到標準錯誤輸出。
? ? ? ? - printStackTrace(PrintStream s):將該異常的跟蹤棧信息輸出到指定輸出流。
? ? ? ? - getStackTrace():返回該異常的跟蹤棧信息。
? ? ? ? 使用finally回收資源:不管try塊中的代碼是否出現(xiàn)異常,也不管哪一個catch塊被執(zhí)行,甚至在try塊或catch塊中執(zhí)行了return語句,finally塊總會被執(zhí)行,用于回收物理資源。
? ? ? ? 塊的必要性與順序:異常處理語法結(jié)構(gòu)中只有try塊是必須的,即沒有try塊,就不能有后面的catch塊和finally塊;catch塊和finally塊至少出現(xiàn)其中之一,也可以同時出現(xiàn);可以有多個catch塊,捕獲父類異常catch塊必須位于捕獲子類異常的后面,否則將出現(xiàn)編譯錯誤;不能只有try塊時,既沒有catch塊,也沒有finally塊;多個catch塊位于try塊之后,finally塊位于所有的catch塊之后。
? ? ? ? 塊中同時包含結(jié)束語句:try塊和catch塊里的return語句和throw語句都會某方法結(jié)束,但是程序會去尋找異常處理流程中是否包含finally塊,如果沒有則立刻執(zhí)行return或throw語句,方法執(zhí)行終止;如果有finally塊,系統(tǒng)立即開始執(zhí)行finally塊,finally塊執(zhí)行完畢后,return或throw語句才會執(zhí)行。如果finally塊里也是用了return或throw語句,則finally塊會終止該方法,try塊和catch塊里的語句將不會執(zhí)行。
? ? ? ? Java7自動關(guān)閉資源的try語句:在try關(guān)鍵字后緊跟一對圓括號,圓括號里可以聲明、初始化一個或多個需要顯式關(guān)閉的資源,try語句會在執(zhí)行結(jié)束后自動關(guān)閉這些資源。這些資源的實現(xiàn)類必須實現(xiàn)了AutoCloseable或Closeable接口的close()方法(AutoCloseable接口的close方法聲明拋出Exception異常,Closeable接口的close方法聲明拋出IOException異常)。自動關(guān)閉資源的try塊相當于包含了隱式的finally塊,因此try語句可以既沒有catch塊,也沒有finally塊。
15.2 Checked異常與Runtime異常????
????????Java程序必須顯式處理Checked異常,要么用使用try...catch塊捕獲該異常,要么拋出該異常;Runtime異常無須顯式聲明拋出,當然也可以使用try...catch塊捕獲該異常。? ? ??
????????使用throws聲明拋出異常:當前方法不知道如何處理該異常時,可以將該異常拋出給上一級調(diào)用者處理;如果main方法無法處理該異常,可以使用throws聲明拋出給Java虛擬機。如果調(diào)用的某個方法,throws了Checked異常,則調(diào)用者必須采取行動。而使用Runtime異常時,程序無須在方法中聲明拋出異常。子類方法聲明拋出的異常類型應該是父類方法聲明拋出的異常類型的子類或相同,子類方法聲明拋出的異常不能比父類方法聲明拋出的異常數(shù)量多。
? ? ? ? 使用throw拋出異常:使用throw拋出一個異常實例,系統(tǒng)同樣會終止程序執(zhí)行查找可以捕獲異常的catch塊。如果拋出的異常是Checked異常,則必須進行處理。如果是Runtime異常,既可以不作處理,也可以try...catch處理或throws拋出。通過catch和throw聯(lián)合使用,可以讓多個方法協(xié)同處理同一個異常。
? ? ? ? 自定義異常類:繼承Exception類或者RuntimeException類,實現(xiàn)無參數(shù)構(gòu)造方法和帶一個字符串消息參數(shù)的方法。
? ? ? ? Java7增強的throw語句:如果拋出一個NumberFormatException異常,catch捕獲時的異常新參是Exception類型,如果想在catch里throw出這個異常并且在方法簽名上throws,在Java7以前只能throws Exception類型;Java7以后,編譯器會檢查throw異常的具體類型,所以可以throws NumberFormatException類型的異常。
? ? ? ? 異常鏈:將捕獲的異常包裝進一個新的異常,并重新拋出異常的方式。JDK1.4以后,所有的Throwable子類在構(gòu)造器中都可以接受一個原始異常作為參數(shù)。使用異常鏈之后,可以追蹤到異常最初發(fā)生的地方。
? ??????Java的異常跟蹤棧:異常對象的printStackTrace()方法用于打印異常的跟蹤棧信息。跟蹤棧記錄所有的異常發(fā)生點等具體信息。
15.3 異常處理規(guī)則
????????- 不要過度使用異常,不要使用異常處理來代替正常的業(yè)務處理邏輯判斷。
? ? ? ? - 不要使用過于龐大的try塊,不便于區(qū)分異常類型,應該對try塊進行分解。
? ? ? ? - 避免使用catch All語句捕獲所有異常。
? ? ? ? - 不要忽略捕獲到的異常,應輸出日志或進行處理。? ? ? ? ?