非常全面的Java異常處理(全文干貨,值得收藏)
一.初始Java異常
1、對異常的理解:異常:在Java語言中,將程序執(zhí)行中發(fā)生的不正常情況稱為“異常”。(開發(fā)過程中的語法錯誤和邏輯錯誤不是異常)
2、Java程序在執(zhí)行過程中所發(fā)生對異常事件可分為兩類:
- Error:Java虛擬機無法解決的嚴重問題。如:JVM系統(tǒng)內(nèi)部錯誤、資源耗盡等嚴重情況。比如:StackOverflowError和OOM。一般不編寫針對性 的代碼進行處理。
- Exception: 其它因編程錯誤或偶然的外在因素導致的一般性問題,可以使用針對性的代碼進行處理。例如:
- 空指針訪問
- 試圖讀取不存在的文件
- 網(wǎng)絡(luò)連接中斷
- 數(shù)組角標越界
3、運行時異常和編譯時異常
運行時異常
- 是指編譯器不要求強制處置的異常。一般是指編程時的邏輯錯誤,是程序員應該積極避免其出現(xiàn)的異常。java.lang.RuntimeException類及它的子類都是運行時異常。
- 對于這類異常,可以不作處理,因為這類異常很普遍,若全處理可能會對程序的可讀性和運行效率產(chǎn)生影響。
編譯時異常
- 是指編譯器要求必須處置的異常。即程序在運行時由于外界因素造成的一 般性異常。編譯器要求Java程序必須捕獲或聲明所有編譯時異常。
- 對于這類異常,如果程序不處理,可能會帶來意想不到的結(jié)果。
二.Error和Exception
1.Error
代碼示例一:java.lang.OutOfMemoryError(堆溢出)
public class ErrorTest { public static void main(String[] args) { //堆溢出:java.lang.OutOfMemoryError Long[] arr = new Long[1024*1024*1024]; } }
運行結(jié)果:
代碼示例二:java.lang.StackOverflowError(棧溢出)
public class ErrorTest { public static void main(String[] args) { //棧溢出:java.lang.StackOverflowError main(args); } }
運行結(jié)果:
2.Exception(運行時異常和編譯時異常)
運行時異常
/* ******************以下是運行時異常****************** */ //ArithmeticException @Test public void test1(){ int num1 = 3; int num2 = 0; int num3 = 3 / 0; } //InputMismatchException @Test public void test2(){ Scanner scanner = new Scanner(System.in); int i = scanner.nextInt(); System.out.println(i); scanner.close(); } //NumberFormatException @Test public void test3(){ String str = "abcd"; int num = Integer.parseInt(str); } //ClassCastException @Test public void test4(){ Object obj = new Boolean(true); String str = (String)obj; } //IndexOutOfBoundsException @Test public void test5(){ ArrayIndexOutOfBoundsException Byte[] bytes = new Byte[3]; System.out.println(bytes[4]); } //NullPointerException @Test public void test6(){ int[] arr = null; System.out.println(arr[1]); }
編譯時異常
/* ******************以下是編譯時異常****************** */ @Test public void test7(){ File file = new File("a.txt"); //java.io.FileNotFoundException FileInputStream fis = new FileInputStream(file); //java.io.IOException int date = fis.read(); while (date != -1){ System.out.println((char)date); date = fis.read(); } fis.close(); }
ps:對于編譯時異常,我們需要異常處理
三.異常處理:抓拋模型
1.抓拋解釋
過程一:“拋”:程序在正常執(zhí)行的過程中,一旦出現(xiàn)異常,就會在異常代碼處生成一個對應異常類的對象, 并將此對象拋出;一旦拋出對象以后,其后的代碼就不再執(zhí)行。
關(guān)于異常對象的產(chǎn)生:
① 系統(tǒng)自動生成的異常對象
② 手動的生成一個異常對象,并拋出(throw)
過程二:“抓”:可以理解為異常的處理方式:① try-catch-finally ② throws
2.try-catch-finally的使用
try{ //可能出現(xiàn)異常的代碼 }catch(異常類型1 變量名1){ //處理異常的方式1 }catch(異常類型2 變量名2){ //處理異常的方式2 }catch(異常類型3 變量名3){ //處理異常的方式3 } … finally{ //一定會執(zhí)行的代碼 }
說明:
- finally是可選的。
- 使用try將可能會出現(xiàn)異常的代碼段包裝起來,在執(zhí)行過程中,一旦出現(xiàn)異常,就會生成一個對應異常類的對象,根據(jù)此對象的類型,去catch中進行匹配
- 一旦try中的異常對象匹配到某一個catch時,就進入catch中進行異常的處理。一旦處理完成,就跳出當前的
try-catch結(jié)構(gòu)(在沒有寫finally的情況)。繼續(xù)執(zhí)行其后的代碼 - catch中的異常類型如果沒有子父類關(guān)系,則誰聲明在上,誰聲明在下無所謂。
catch中的異常類型如果滿足子父類關(guān)系,則要求子類一定聲明在父類的上面。否則,報錯 - 常用的異常對象處理的方式: ① String getMessage() ② printStackTrace()
- 在try結(jié)構(gòu)中聲明的變量,再出了try結(jié)構(gòu)以后,就不能再被調(diào)用
- try-catch-finally結(jié)構(gòu)可以嵌套
- finally中聲明的是一定會被執(zhí)行的代碼。即使catch中又出現(xiàn)異常了,try中有return語句,catch中有return語句等情況。
- 像數(shù)據(jù)庫連接、輸入輸出流、網(wǎng)絡(luò)編程Socket等資源,JVM是不能自動的回收的,我們需要自己手動的進行資源的釋放。此時的資源釋放,就需要聲明在finally中。
示例一:
@Test public void test1(){ String str = "abcd"; int num = 1314; try { num = Integer.parseInt(str); System.out.println("進入try代碼塊!"); }catch (NumberFormatException e){ System.out.println("出現(xiàn)數(shù)值轉(zhuǎn)換異常了!"); System.out.println(e.getMessage()); e.printStackTrace(); System.out.println("該catch語句塊將要執(zhí)行完了!"); } catch (NullPointerException e){ System.out.println("出現(xiàn)空指針異常!"); } catch (Exception e){ System.out.println("出現(xiàn)異常了"); }finally { System.out.println("執(zhí)行finally語句了!"); } System.out.println(num); }
輸出結(jié)果:
示例二:
@Test public void test2(){ File file = new File("a.txt"); FileInputStream fis = null; try { fis = new FileInputStream(file); int date = fis.read(); while(date != -1){ System.out.println((char)date); date = fis.read(); } } catch (FileNotFoundException e) { e.printStackTrace(); }catch (IOException e){ e.printStackTrace(); }finally { System.out.println("執(zhí)行finally語句了!"); try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } }
輸出結(jié)果:
總結(jié):
- 使用try-catch-finally處理編譯時異常,是得程序在編譯時就不再報錯,但是運行時仍可能報錯。相當于我們使用try-catch-finally將一個編譯時可能出現(xiàn)的異常,延遲到運行時出現(xiàn)。
- 開發(fā)中,由于運行時異常比較常見,所以我們通常就不針對運行時異常編寫try-catch-finally了。針對于編譯時異常,我們說一定要考慮異常的處理。
3.throws + 異常類型的使用
"throws + 異常類型"寫在方法的聲明處。指明此方法執(zhí)行時,可能會拋出的異常類型。一旦當方法體執(zhí)行時,出現(xiàn)異常,仍會在異常代碼處生成一個異常類的對象,此對象滿足throws后異常類型時,就會被拋出。異常代碼后續(xù)的代碼,就不再執(zhí)行!
try-catch-finally:真正的將異常給處理掉了。
throws的方式只是將異常拋給了方法的調(diào)用者。 并沒有真正將異常處理掉。
子類重寫的方法拋出的異常類型不大于父類被重寫的方法拋出的異常類型(子類重寫的方法也可以不拋出異常)
public class SuperClass { public void method() throws IOException { } } class SubClass extends SuperClass{ //報錯,子類重寫的方法拋出的異常類型不大于父類被重寫的方法拋出的異常類型 // public void method() throws Exception{ // // } public void method() throws FileNotFoundException{ } }
開發(fā)中如何選擇使用try-catch-finally 還是使用throws? 如果父類中被重寫的方法沒有throws方式處理異常,則子類重寫的方法也不能使用throws,意味著如果
子類重寫的方法中有異常,必須使用try-catch-finally方式處理。執(zhí)行的方法a中,先后又調(diào)用了另外的幾個方法,這幾個方法是遞進關(guān)系執(zhí)行的。我們建議這幾個方法使用throws
的方式進行處理。而執(zhí)行的方法a可以考慮使用try-catch-finally方式進行處理。
代碼示例:
public class ErrorThrows { public static void method1() throws IOException { File file = new File("a.txt"); FileInputStream fileInputStream = new FileInputStream(file); int data = fileInputStream.read(); while(data != -1){ System.out.println((char)data); data = fileInputStream.read(); } fileInputStream.close(); } public static void method2() throws IOException { method1(); } public static void method3() throws IOException { method1(); } public static void main(String[] args) { try { method3(); } catch (IOException e) { e.printStackTrace(); } } }
4.手動拋出一個異常類對象(throw關(guān)鍵字使用)
代碼示例:
public class ReturnException { static void method1(){ try{ System.out.println("進入方法1"); throw new RuntimeException("手動拋出異常"); }catch (Exception e){ e.printStackTrace(); System.out.println(e.getMessage()); } finally { System.out.println("執(zhí)行finally語句了!"); } } public static void main(String[] args) { method1(); } }
輸出結(jié)果:
四.自定義異常類
自定義異常類,有如下三步驟:
- 繼承于現(xiàn)有的異常結(jié)構(gòu):RuntimeException 、Exception
- 提供全局常量:serialVersionUID
- 提供重載的構(gòu)造器
自定義異常類:
public class MyExceptionClass extends Exception{ static final long serialVersionUID = -5641210210148784L; public MyExceptionClass() { } public MyExceptionClass(String message) { super(message); } }
手動拋出上述自定義的異常類對象:
public class MyExceptionTest { static void method1() throws MyExceptionClass { Scanner scanner = new Scanner(System.in); System.out.println("請輸入大于0的數(shù)據(jù):"); double next = scanner.nextDouble(); if(next >0){ System.out.println("您輸入的數(shù)據(jù)為:"+next); }else { throw new MyExceptionClass("您輸入的數(shù)據(jù)不滿足要求!"); } } public static void main(String[] args) { try { method1(); } catch (MyExceptionClass myExceptionClass) { myExceptionClass.printStackTrace(); } } }
運行結(jié)果:
到此這篇關(guān)于非常全面的Java異常處理的文章就介紹到這了,更多相關(guān)Java異常處理干貨內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java使用jdbc連接MySQL數(shù)據(jù)庫實例分析
這篇文章主要介紹了Java使用jdbc連接MySQL數(shù)據(jù)庫,結(jié)合實例形式分析了Java基于jdbc鏈接mysql的相關(guān)配置及工具類的定義相關(guān)操作技巧,需要的朋友可以參考下2018-07-07Mybatis如何傳入多個參數(shù)的實現(xiàn)代碼
這篇文章主要介紹了Mybatis如何傳入多個參數(shù)的實現(xiàn)代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-12-12如何通過ServletInputStream讀取http請求傳入的數(shù)據(jù)
這篇文章主要介紹了如何通過ServletInputStream讀取http請求傳入的數(shù)據(jù),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-10-10Java?Stream函數(shù)式編程管道流結(jié)果處理
這篇文章主要為大家介紹了Java?Stream函數(shù)式編程管道流結(jié)果處理的示例過程解析需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步2022-03-03詳解Java的Hibernate框架中的set映射集與SortedSet映射
這篇文章主要介紹了詳解Java的Hibernate框架中的set映射集與SortedSet映射,Hibernate是Java的SSH三大web開發(fā)框架之一,需要的朋友可以參考下2015-12-12Java String、StringBuffer與StringBuilder的區(qū)別
本文主要介紹Java String、StringBuffer與StringBuilder的區(qū)別的資料,這里整理了相關(guān)資料及詳細說明其作用和利弊點,有需要的小伙伴可以參考下2016-09-09