1.傳統(弱語言)處理異常方式
原理:利用判斷來控制異常出現
1 publicclass Test01 { 2 publicstaticvoid main(String[] args) { 3 Scanner sc = new Scanner(System.in); 4 System.out.println("請輸入第一個數:"); 5 6 intnum1 = 0; 7 if(sc.hasNextInt()) { 8 num1 = sc.nextInt(); 9 10 System.out.println("請輸入第二個數:"); 11 intnum2 = 0; 12 if(sc.hasNextInt()) { 13 num2 = sc.nextInt(); 14 15 if(0 == num2) { 16 System.out.println("除數不能為0!"); 17 }else { 18 intr = num1 / num2; 19 System.out.println("num1/num2 = "+r); 20 } 21 22 }else { 23 System.out.println("第二個數輸入不是數字"); 24 } 25 26 }else { 27 System.out.println("第一個數輸入不是數字!"); 28 } 29 } 30 }
這樣做的缺點:
【1】通過判斷處理異常影響執行效率。
【2】判斷邏輯和業務邏輯交織在一起,不利於后期維護。
2.異常
異常是所有異常類的直接或間接父類。
異常是指在運行過程中發生了不正常的情況,這是它就會中斷程序。
異常處理機制:指java中異常處理機制為程序提供處理異常的能力,從而使程序不中斷的運行。
3.異常處理
異常處理的關鍵字有:try...catch 和 try...catch...finally
1)try...catch
解釋:try— 把有可能產生異常的代碼放到try代碼塊中,catch—負責捕獲異常並匹配異常再處理異常。
【1】正常執行,沒有遇到異常
【2】出現異常,異常處理,正常結束。(紅字是處理異常步驟)
異常常見方法:
prinStackTrace:打印異常的執行堆棧信息(在控制台中異常堆棧信息輸出位置不固定)
1 java.util.InputMismatchException 2 at java.util.Scanner.throwFor(Scanner.java:864) 3 at java.util.Scanner.next(Scanner.java:1485) 4 at java.util.Scanner.nextInt(Scanner.java:2117) 5 at java.util.Scanner.nextInt(Scanner.java:2076) 6 at cn.sxt02.exception02.Test01.main(Test01.java:14)
一般,異常的堆棧信息很多,開發者只需要看懂
——第一行:異常簡單的信息(異常類型,異常描述等)
——最后一行:異常出現的位置(如上的Test01.java:14)
getMessage:返回異常的描述信息
1 packagecn.sxt02.exception02; 2 importjava.util.Scanner; 3 publicclass Test01 { 4 publicstaticvoid main(String[] args) { 5 Scanner sc = new Scanner(System.in); 6 System.out.println("請輸入第一個數:"); 7 8 intnum1 = 0; 9 intnum2 = 0; 10 11 try { 12 num1 = sc.nextInt(); 13 14 System.out.println("請輸入第二個數:"); 15 num2 = sc.nextInt(); 16 17 intr = num1 / num2; 18 System.out.println("num1/num2 = " + r); 19 }catch (Exception e) { 20 System.out.println("程序出現異常"); 21 // 打印異常的信息 22 // System.out.println(e.toString()); 23 24 25 // 打印異常堆棧信息 26 e.printStackTrace(); 27 28 // 返回異常的描述信息,如果沒有信息,返回null(InputMismatchException沒有描述信息) 29 System.out.println(e.getMessage()); 30 } 31 32 System.out.println("程序正常結束"); 33 }
【3】異常類型不匹配
【4】多重catch
1 publicclass Test03 { 2 publicstaticvoid main(String[] args) { 3 Scanner sc = new Scanner(System.in); 4 System.out.println("請輸入第一個數:"); 5 6 intnum1 = 0; 7 intnum2 = 0; 8 9 try { 10 num1 = sc.nextInt(); 11 12 System.out.println("請輸入第二個數:"); 13 num2 = sc.nextInt(); 14 15 intr = num1 / num2; 16 System.out.println("num1/num2 = " + r); 17 }catch (ArithmeticExceptione) { 18 System.out.println("數學計算異常:"+e.getMessage()); 19 }catch(InputMismatchExceptione) { 20 System.out.println("輸入不匹配異常:"+e.getMessage()); 21 }catch (Exception e) { 22 System.out.println("發送異常:"+e.getMessage()); 23 } 24 25 System.out.println("程序正常結束"); 26 } 27 }
2)try...catch...finally
解讀:把有可能產生異常的代碼放到try的代碼塊中,catch捕捉異常並匹配異常再處理異常,finally塊用於收尾工作
(如關閉數據庫,關閉文件,釋放內存等資源)
注:finally :無論是否發生異常,finally都將執行,常用於收尾工作
1 publicstaticvoid main(String[] args) { 2 Scanner sc = new Scanner(System.in); 3 System.out.println("請輸入第一個數:"); 4 5 intnum1 = 0; 6 intnum2 = 0; 7 8 try { 9 num1 = sc.nextInt(); 10 11 System.out.println("請輸入第二個數:"); 12 num2 = sc.nextInt(); 13 14 intr = num1 / num2; 15 System.out.println("num1/num2 = " + r); 16 } catch (Exception e) { 17 System.out.println("程序出現異常"); 18 } finally { 19 System.out.println("不管是否出現異常,finally都執行"); 20 } 21 22 System.out.println("程序正常結束"); 23 }
特殊情況:
【1】finally不執行的情況
System.exit(0)正常退出jvm,程序結束,不會執行finally
【2】catch可以省略,變成try...finally形式
4.return
當return存在於try...catch...finally時的執行順序(return始終在最后)
1 packagecn.sxt02.exception03; 2 3 /** 4 * 存在return的情況 5 */ 6 publicclass Test02 { 7 8 publicstaticintdiv(inta, intb) { 9 10 try { 11 intr = a / b; 12 returnr; 13 14 } catch (Exception e) { 15 System.out.println("出現異常"); 16 17 return 0; 18 19 } finally { 20 System.out.println("我是finally"); 21 } 22 23 } 24 25 publicstaticvoid main(String[] args) { 26 27 intr = Test02.div(10, 0); 28 System.out.println("r=" + r); 29 System.out.println("程序正常結束"); 30 } 31 }
5.異常的分類
Throwable類是 Java 語言中所有錯誤(Error)或異常(Exception)的父類,只有當對象是此類(或其子類之一)的實例時,才能通過 Java 虛擬機或者 Java throw 語句拋出。
Error 類表示錯誤類。僅靠程序本身無法恢復的嚴重錯誤。如jvm內存耗盡、jvm崩潰等。
Exception類表示異常類,可以通過java 異常處理機制處理。
Exception根據是否處理分為兩種情況。
RuntimeException:運行時異常。不要求程序必須做出處理。是所有運行時異常的父類。
CheckedException:檢查時異常。要求程序必須處理,不處理編譯不通過。
1 publicclass Test01 { 2 publicstaticvoid main(String[] args) { 3 // 運行時異常 4 Scanner sc = new Scanner(System.in); 5 // runtime exception 6 intr = sc.nextInt(); 7 System.out.println("r = "+ r); 8 9 // 檢查時異常 10 SimpleDateFormatdf = newSimpleDateFormat(); 11 try { 12 Date date = df.parse("2019"); 13 } catch (ParseExceptione) { 14 e.printStackTrace(); 15 } 16 } 17 }
常見的運行時異常
ArithmeticException:數學計算異常。如除數為0
InputMismatchException:輸入不匹配異常。
ArrayIndexOutofBoundsException:數組下標越界異常。
NullPointException:空指針異常,對象沒有初始化就使用時,jvm就會拋出該異常。
IllegalArgumentException:非法參數異常。
ClassCastException:強制類型轉化異常。
NumberFormatException:數字格式化異常。如把“abc”格式化為數字。
常見的檢查時異常:
ClassNotFoundException:類沒有被發現異常。
SQLException:數據庫相關異常
IOException:IO操作異常
ParseException:解析錯誤異常
FileNotFoundException:文件未發現異常。
運行時異常和檢查時異常的區別:
運行時異常:包括RuntimeException及其所有子類。不要求程序必須對它們作出處理,比如InputMismatchException、 ArithmeticException、NullPointerException等。即使沒有使用try-catch或throws進行處理,仍舊可以進行
編譯和運行。如果運行時發生異常,會輸出異常的堆棧信息並中止程序執行。
檢查時異常:Checked異常(非運行時異常):除了運行時異常外的其他異常類都是Checked異常。程序必須捕獲或者
聲明拋出這種異常,否則出現編譯錯誤,無法通過編譯。處理方式包括兩種:通過try-catch捕獲異常,
通過throws聲明拋出異常從而交給上一級調用方法處理
6.聲明異常
1)throws關鍵字
解讀:當一個方法可能存在異常,而此時自身又無法更好的處理,可以交給外界處理。此時用throws聲明並拋出異常。
1 publicclass Test01 { 2 3 publicstaticintdiv(inta, intb) throws ArithmeticException{ 4 intr = 0; 5 r = a / b; 6 returnr; 7 } 8 9 publicstaticvoid main(String[] args) { 10 try { 11 Test01.div(10, 0); 12 } catch (ArithmeticExceptione) { 13 System.out.println("除數不能為0"); 14 } 15 } 16 }
注:開發者可以根據需求聲明檢查時異常 (Exception或者非運行時異常及其子類) 和運行時異常(RuntimeException或其子類)
如果拋出異常后,調用處不知道如何處理異常,可以選擇繼續聲明異常(拋出異常),這個過程叫做異常上拋。
1 publicclass Test01 { 2 3 publicstaticintdiv(inta, intb) throws Exception{ 4 intr = 0; 5 r = a / b; 6 returnr; 7 } 8 9 publicstaticvoid main(String[] args) throws Exception{ 10 11 //【1】調用處知道如何處理! 12 /* 13 try { 14 Test01.div(10, 0); 15 } catch (Exception e) { 16 e.printStackTrace(); 17 } 18 */ 19 20 // 【2】調用處也不知道如何處理 21 Test01.div(10, 0); 22 23 } 24 }
2)聲明異常和重載的關系
聲明異常和重載沒有任何關系
1 publicclass Test01 { 2 3 publicstaticintdiv(inta, intb) throws Exception{ 4 intr = 0; 5 r = a / b; 6 returnr; 7 } 8 9 publicstaticintdiv(inta, intb) { 10 intr = 0; 11 r = a / b; 12 returnr; 13 } 14 }
注:方法重載:
【1】方法名相同
【2】參數列表不同(個數,類型,不同類型的順序不同)
【3】和返回值,修飾符,聲明異常無關
3)聲明異常和重寫的關系
聲明異常和方法重寫有關系,關系如下
[1]父類方法聲明了異常(檢測時或運行時),子類可以不聲明任何異常。
publicclass Father { publicvoidshowInfo() throws Exception{ } }
publicclass Son extendsFather{
@Override
publicvoidshowInfo(){
}
}
理解:父類方法拋出異常,子類在重寫過程中把該異常處理掉了,所以子類方法不用聲明異常。
[2] 父類方法聲明沒有聲明任何異常(檢測時或運行時),子類也不聲明異常或者聲明運行時異常。
publicclass Father {
publicvoidshowInfo(){
}
}
publicclass Son extendsFather{ @Override publicvoidshowInfo() throws Exception{ } }
[3]父類聲明了異常(檢測時或運行時),子類聲明完全一樣的異常。
publicclass Father {
publicvoidshowInfo() throwsException{
}
}
publicclass Son extendsFather{
@Override
publicvoidshowInfo() throwsException {
}
}
7.手動拋出異常
1)throw
除了系統自動拋出異常外,有些問題需要開發者手動拋出異常。使用關鍵字throw
1 packagecn.sxt02.exception06; 2 3 publicclass Student { 4 private String name; 5 private String gender; 6 7 public String getName() { 8 returnname; 9 } 10 11 publicvoidsetName(String name) { 12 this.name = name; 13 } 14 15 public String getGender() { 16 returngender; 17 } 18 19 publicvoidsetGender(String gender) throws Exception{ 20 if(gender.equals("男") || gender.equals("女")) { 21 this.gender = gender; 22 }else { 23 thrownew Exception("性別不合法!"); 24 } 25 } 26 27 publicStudent(String name, String gender) { 28 super(); 29 this.name = name; 30 this.gender = gender; 31 } 32 33 publicStudent() { 34 super(); 35 } 36 37 }
1 publicclass Test01 { 2 publicstaticvoid main(String[] args){ 3 Student stu = newStudent(); 4 stu.setName("二狗"); 5 try { 6 stu.setGender("xxx"); 7 } catch (Exception e) { 8 System.out.println(e.getMessage()); 9 } 10 } 11 }
2)自定義異常
理解:如果開發者需要手動拋出的異常在系統不存在,可以自定義異常。
注意:如果要自定義異常,首先要確定異常類型,如果異常是運行時異常,必須繼承RuntimeException或其子類;如果異常是檢查時異常,必須繼承Exception或其子類。
——異常的命名方式,參考系統命名方式,以Exception結尾。
publicclassAgeExceptionextendsException{ publicAgeException() { super(); } publicAgeException(String message) { super(message); } }