Java異常的處理機制
圖片解析:
1.生成字節(jié)碼文件的過程可能產(chǎn)生編譯時異常(checked),由字節(jié)碼文件到在內(nèi)存中加載、運行類此過程可能產(chǎn)生運行時異常(unchecked),
2.JAVA程序在執(zhí)行過程中所發(fā)生的異常事件可分為兩類:
> Error: Java虛擬機無法解決的的嚴重問題。如:JVM系統(tǒng)內(nèi)部錯誤、資源耗盡等嚴重情況。比如:StackOverflowError和OOM.一般不編寫針對性的代碼進行處理。
> Exception: 其他因編程錯誤或偶然的外在因素導致的一般性問題,可以使用針對性的代碼進行處理。例如:
空指針訪問、試圖讀取不存在的文件、網(wǎng)絡連接中斷、數(shù)組角標越界
捕獲錯誤最理想的實在編譯期間,但有的錯誤只有在運行時才會發(fā)生。比如:除數(shù)為0,數(shù)組角標越界等
編譯時異常(執(zhí)行javac.exe命令時,可能出現(xiàn)的異常):IOException、FileNotFoundException(IOException的子類)、 ClassNotFoundException
運行時異常(執(zhí)行java.exe命令時,出現(xiàn)的異常):NullPointerException、ArrayIndexOutOfBoundsException、ArrayIndexOutOfBoundsException、ClassCastException、NumberFormatException、InputMismatchException、ArithmeticException
public class ExceptionTest{ //NullPointerException @Test public void test1(){ int[] arr = null; System.out.println(arr[3]); str = null; System.out.println(str.charAt(0)); } //IndexOutOfBoundsException @Test public void test2(){ //ArrayIndexOutOfBoundsException int[] arr = new int[10]; System.out.println(arr[10]); //StringIndexOutOfBoundsException str = "abc"; System.out.println(str.charAt(3)); } //ClassCastException:類型不匹配 @Test public void test3(){ Object obj = new Date(); String str = (String)obj; } //NumberFormatException:數(shù)據(jù)格式異常 @Test public void test4(){ str = "abc"; int num = Integer.parseInt(str); } //InputMismatchException:輸入不匹配異常 @Test public void test5(){ Scanner scanner = new Scanner(System.in); int score = scanner.nextInt(); System.out.println(score); } //ArithmeticException:算數(shù)異常 @Test public void test6(){ int a = 10; int b= 0; System.out.println(a\b); } }
異常的處理:
在編寫程序時,經(jīng)常要在可能出現(xiàn)錯誤的地方加上檢測的代碼,如進行x/y運算時,要檢測分母為0,數(shù)據(jù)為空,輸入的不是數(shù)據(jù)而是字符等。過多的if-case分支會導致程序的代碼加長,臃腫,可讀性差,因此采用異常處理機制。
Java采用的異常處理機制,是將異常處理的程序代碼集中在一起,與正常的程序代碼分開,使得程序 簡潔、優(yōu)雅,并易于維護。
異常的處理:抓拋模型
過程一:"拋":程序在正常執(zhí)行的過程中,一旦出現(xiàn)異常,就會在異常代碼處生成一個對應異常類的對象,并將此對象拋出。一旦拋出以后,其后的代碼就不再執(zhí)行。
關于異常對象的產(chǎn)生:A. 系統(tǒng)自動生成的異常對象
B. 手動的生成一個異常對象,并拋出(throw)
過程二:"抓":可以理解為異常的處理方式:A.try-catch-finally B.throws
強調(diào):過程一和過程二屬于配合的方式,是并列關系
處理機制一:try-catch-finally
try{ //可能出現(xiàn)異常的代碼 }catch(異常類型1 變量名1){//一段代碼可能有多個異常類型 //處理異常的方式1 }catch(異常類型2 變量名2){ //處理異常的方式2 }catch(異常類型3 變量名3){ //處理異常的方式3 } ..... finally{ //一定會執(zhí)行的代碼 }
說明:
1.finally是可選的(可有,也可沒有,不會影響異常的處理)
2.使用try將可能出現(xiàn)異常代碼包裝起來,在執(zhí)行過程中,一旦出現(xiàn)異常,就會生成一個對應異常類的對象,根據(jù)此對象的類型,去catch中進行匹配。
3.一旦try中的異常對象匹配到某一個catch時,就進入catch中進行異常的處理,一旦處理完成,就跳出當前的try-catch結(jié)構(在沒有寫finally的情況)。繼續(xù)執(zhí)行其后的代碼。
4.catch中的異常類型如果沒有子父類的關系,則誰生命在上,誰聲明在下無所謂。
catch中的異常類型如果滿足子父類的關系,則要求子類一定聲明在父類的上面,否則,報錯
5.常用的異常對象處理的方式:
A.(返回值時String,可以用輸出語句查看)getMessage()
B.(開發(fā)中常用)printStackTrace()
6.在try結(jié)構中聲明的變量:再出了try結(jié)構以后,就不能在被調(diào)用
7.try-catch-finally結(jié)構可以嵌套
體會1:使用try-catch-finally處理編譯時異常,使得程序在編譯時就不再報錯,但是運行時仍可能報錯。相當于我們使用try-catch-finally將一個編譯時可能出現(xiàn)的異常,延遲到運行時出現(xiàn)(即把編譯時異常轉(zhuǎn)換為運行時異常)
體會2:開發(fā)中由于運行時異常比較常見,所以我們通常就不針對運行時異常編寫try-catch-finally了,針對編譯時異常,我們一定要考慮異常的處理。
@Test public void test1() { str = "abc"; int num = 0;// 聲明放在外面,出了try,還可以使用num; //但是此時要注意:在try-catch結(jié)構中,num不一定被賦值,所以要手動的給賦默認初始化值 try { num = Integer.parseInt(str); } catch (NullPointerException e) { System.out.println(e.getMessage()); } catch (NumberFormatException e) { e.printStackTrace(); } System.out.println(num); }
finally的再說明:
1. finally是可選的
2.finally中聲明的是一定會被執(zhí)行的代碼,即使catch中又出現(xiàn)異常了、try中有return語句、catch中有return語句等情況。
3.finally中一定會執(zhí)行的結(jié)構在加載順序上優(yōu)于try、catch中的異常代碼
@Test//catch中又出現(xiàn)異常了 public void test1(){ try{ int a = 10; int b = 0; System.out.println(a / b); }catch(ArithmeticException e){ int[] arr = new int[10]; System.out.println(arr[10]); } //System.out.println("catch中又出現(xiàn)異常了,但我一定不會輸出!"); finally{ System.out.println("catch中又出現(xiàn)異常了,但我一定會輸出!"); } }
@Test//try中有return語句、catch中有return語句 public void testMethod(){ int num = method(); } public int method(){ try{ int[] arr = new int[10]; System.out.println("arr[10]"); return 1; }catch(ArrayIndexOutOfBoundException e){ e.printStockTrace(); return 2; }finally{ System.out.println("我一定會被執(zhí)行!"); return 3; } } //finally中一定會執(zhí)行的結(jié)構在執(zhí)行順序上優(yōu)于try、catch中的return語句 //由于方法只能有一個返回值,所以最后返回的是return 3;
3.像數(shù)據(jù)庫連接、輸入輸出流、網(wǎng)絡編程Socket等資源,JVM是不能自動的回收的,我們需要自己手動的進行資源的釋放。此時,就需要聲明在finally中。
處理機制二:throws + 異常類型
1. "throws + 異常類型"寫在方法的聲明處,指明此方法執(zhí)行時,可能會拋出的異常類型。
一旦當方法體執(zhí)行時,出現(xiàn)異常,仍會在異常代碼處生成一個異常類的對象,此對象滿足throws后異常類型時,就會被拋出。異常代碼后續(xù)的代碼,就不再執(zhí)行!
2.體會:try-catch-finally:真正的將異常給處理掉了.(以后在其他方法中調(diào)用含有異常的方法時,不會報編譯時錯誤了)
throws的方式只是將異常拋給了方法的調(diào)用者。并沒有真正將異常處理掉。(拋至main時,必須處理掉,不然拋給JVM,JVM就掛了)
public class ExceptionTest2 { public static void main(String[] args) { try { method2(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } method3();// 在method2()里已經(jīng)解決了異常,所以可以調(diào)用 } public static void method3() { try { method2(); } catch (IOException e) { e.printStackTrace(); } } public static void method2() throws FileNotFoundException, IOException { method1(); } public static void method1() throws FileNotFoundException, IOException {//異常代碼 File file = new File("hello.txt"); FileInputStream fis = new FileInputStream(file); int data = fis.read(); while (data != -1) { System.out.print((char) data); data = fis.read(); } fis.close(); System.out.println("hanhan");// 不會被執(zhí)行! } }
方法重寫的規(guī)則之一:
子類重寫的方法拋出的異常類型不大于父類被重寫的方法拋出的異常類型
意味著:如果父類中沒有出現(xiàn)異常,則子類中也不能有異常
我的理解:針對Java中的異常,如果時編譯時異常,則需要將其延遲為運行時異常,異常處理機制的作用也就是這樣,目的是為了給程序員一個提示,運行時異常的根本還是修改代碼。
手動拋出異常對象
public class StudentTest { public static void main(String[] args) { Student s = new Student(); s.regist(-1001); System.out.println(s); } } class Student { private int id; public void regist(int id) { if (id > 0) { this.id = id; } else {//方式一:拋出運行時異常,運行時會報錯 // 手動拋出異常對象 throw new RuntimeException("您輸入的數(shù)據(jù)非法!"); } } }
public class StudentTest { public static void main(String[] args) { try { Student s = new Student(); s.regist(-1001); System.out.println(s); } catch (Exception e) { System.out.println(e.getMessage()); } } } class Student { private int id; public void regist(int id) throws Exception {//throws:體現(xiàn)異常的處理 if (id > 0) { this.id = id; } else {//拋出編譯時異常:必須顯式的處理 throw new Exception("您輸入的數(shù)據(jù)非法!");//throw:體現(xiàn)生成一個異常對象 } } }
開發(fā)中應該如何選擇兩種處理方式?
1. 如果父類中被重寫的方法沒throws方式處理異常,則子類重寫的方法也不能使用throws,意味著如果子類重寫的方法中異常,必須使用try-catch-finally方式處理。
2.執(zhí)行的方法a中,先后有調(diào)用了另外的幾個方法,這幾個方法時遞進關系執(zhí)行的,我們建議這幾個方法使用throws的方式進行處理,而執(zhí)行的方法a可以考慮使用try-catch-finally方式進行處理。
用戶自定義異常類
如何自定義異常類?
1.繼承于現(xiàn)有的異常結(jié)構:RuntimeException、Exception
2.提供全局變量:serialVersionUID
3.提供重載的構造器
public class StudentTest { public static void main(String[] args) { try { Student s = new Student(); s.regist(-1001); System.out.println(s); } catch (Exception e) { System.out.println(e.getMessage()); } } } class Student { private int id; public void regist(int id) throws Exception { if (id > 0) { this.id = id; } else { throw new MyException("不能輸入負數(shù)");//自定義異常類的使用 } } } public class MyException extends RuntimeException {//自定義異常類 static final long serialVersionUID = -7034897190745766939L; public MyException() { } public MyException(String msg) { super(msg); } }
throw和throws的區(qū)別:
throw:表示拋出一個異常類的對象,生成異常對象的過程,聲明在方法體內(nèi)。
throws:屬于異常類處理的一種方式,聲明在方法的聲明處
到此這篇關于Java異常的處理機制的文章就介紹到這了,更多相關Java 異常內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
springboot+rabbitmq實現(xiàn)指定消費者才能消費的方法
當項目部署到測試環(huán)境后,QA測試過程中,總是“莫名其妙”的發(fā)現(xiàn)所保存的用戶付款單數(shù)據(jù)有問題。這篇文章主要介紹了springboot+rabbitmq實現(xiàn)指定消費者才能消費,需要的朋友可以參考下2021-11-11Spring Boot2.x集成JPA快速開發(fā)的示例代碼
這篇文章主要介紹了Spring Boot2.x集成JPA快速開發(fā),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-05-05SpringBoot?Test的webEnvironment源碼解讀
這篇文章主要為大家介紹了SpringBoot?Test的webEnvironment源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-09-09Java中String.format的使用方法總結(jié)
這篇文章主要介紹了Java中String.format的用法總結(jié)的相關資料,需要的朋友可以參考下2017-03-03