異常處理 異常分類與體繫結構: Error 相關類型的異常是程式無法處理(大多都是修改代碼無法解決的)的異常,這類異常通常需要我們調整JVM的運行環境 Exception 相關類型的異常是程式可以處理的異常,其包含兩大子類型 編譯異常(CheckedException) 通常是語法錯誤,或是方法明確 ...
異常處理
異常分類與體繫結構:
Error 相關類型的異常是程式無法處理(大多都是修改代碼無法解決的)的異常,這類異常通常需要我們調整JVM的運行環境
Exception 相關類型的異常是程式可以處理的異常,其包含兩大子類型
編譯異常(CheckedException)
通常是語法錯誤,或是方法明確指明可能拋出異常則必須捕獲處理
運行時異常(RuntimeException)
指的是檢查階段沒有發現任何問題,滿足所有語法規範,只有在運行時才能發現的異常
異常處理
關鍵字 try catch finally throws throw
基本語法:
註意:
- try 無法單獨使用,必須與catch 或finally 組合使用
finally 表示最終,即無論異常是否真的發生了,最終都會執行finally
- 當異常類型為Exception時 表示通用異常處理(萬能異常處理),可以捕獲所有異常但是無法針對性的處理
- 一個try可以有多個catch
- 通常將Exception添加到最後一個catch中作為完全保證,讓程式可以繼續運行
- 一個try中的所有catch下每個異常類型只能出現一次
- catch中異常類型必須從小到大(先子類在父類)
- 無論有多個catch最終只有一個會被執行(類似 if else.....)
如要打斷finally的執行可以直接退出虛擬機,System.exit();
finally 對return的影響
在方法中,如果有finally,即使在 try 或catch中遇到了return 語句,方法也不會立即結束,而是必須執行完finally後才會執行結束,
案例:
class Test{
public static void main(String[] args){
System.out.println(func(0));
//此處得到的結果為10000;
//如果沒有finally 則是10;
}
public static int func(int arg){
try{
int a = 1/arg;
return a;
}catch(Exception e){
return 10;
}finally{
return 10000;
}
}
}
強調:方法中無論是否出現異常,返回值都以finally中的返回值為準,這是不符合實際的,所以通常不這麼寫
拋出異常
throws
用於方法定義,在定義方法時可以使用throws來聲明,方法可能會拋出某種類型的異常
什麼時候使用throws
當方法中可能會有異常,但是方法本身無法處理,或是不想處理....就可以使用throws來拋出
需要強調的是:如果一個異常拋出後沒最終沒有得到處理,將導致程式運行中斷,所以通常我們不能放任不管
使用
註意:
簡單的說,只要聲明瞭,則表明方法內部不會處理該異常,誰調用就由誰處理;
- 相應的調用者則需要捕獲異常並處理,若調用方也無法處理,則可以繼續向上拋出
一個方法也可以聲明拋出多種不同類型異常,響應的調用方應增加對應的catch
案例:
package com.yh.test;
public class Test {
public static void main(String[] args){
//一直拋向程式入口都沒有得到處理則程式被終止
func3();
}
static public void func2() throws ArithmeticException{
int a = 1/0;
}
static public void func3() throws ArithmeticException{
try{
func2();//func2拋出異常
}catch (Exception e){
//無法處理則繼續向上拋出
throw e;
}
}
}
拋出多種類型異常:
import java.util.InputMismatchException;
import java.util.Scanner;
public class Test {
public static void main(String[] args){
try {
func3();
} catch (ArrayIndexOutOfBoundsException e) {
e.printStackTrace();
} catch (InputMismatchException e) {
e.printStackTrace();
}
}
static public int func3() throws ArrayIndexOutOfBoundsException,InputMismatchException{// try{
int a = new Scanner(System.in).nextInt();
return 10/a;
}
}
throw
主動拋出異常
使用場景:
當方法的提供者需要調用者提供一些數據,但是這些數據不合法,導致功能無法正常處理時,就應該主動拋出異常
調用方可以在捕獲到異常後進行處理
拋出還是處理?
方法內部導致的異常自己處理,調用者導致的異常則拋出(或者能處理則處理)
疑惑:為什麼throws Exception時編譯器要求必須提供解決方案?
因為Exception 既包含了運行時異常 又包含了 編譯時異常,所以要求必須處理,由此可知,當throws聲明的異常為編譯時異常時則要求必須提供處理代碼;
案例:
package com.yh.test;
public class Test {
public static void main(String[] args){
try {
func(1);
} catch (Exception e) {
e.printStackTrace();
}
}
static void func(int a) throws Exception{
if (a < 1){
throw new Exception("參數不能小於1");
}
}
}
自定義異常
當內置異常無法滿足特點業務場景時,可以自定義異常類,只需要繼承Exception即可
案例:
class MyException extends Exception{
public MyException() {
super("固定的異常提示!");
}
}
當異常提示信息固定的時候可以像上面一樣定義構造器
異常鏈
當一個方法拋出的異常被調用方法捕獲,但是調用方法又拋出了新的異常時,則形成了異常鏈,
如果我們在調用方法中直接拋出新的異常不做任何額外的操作時,原始異常信息則被丟失;
我們有兩個方法可以保留原始異常信息
1.實例化時使用原始異常作為參數
2.實例化後調用initCause傳入原始異常對象
案例:
package com.yh.test;
public class ExceptionLinkeTest {
public static void main(String[] args) {
try {
func2();
} catch (Exception e) {
e.printStackTrace();
}
}
static public void fun1() throws ArithmeticException{
int a = 1 / 0;
}
static public void func2() throws Exception{
try{
fun1();
}catch (ArithmeticException e){
//不保留原始異常信息
//throw new Exception("新的異常信息!");
//保留異常信息方法1
throw new Exception("新的異常信息!",e);
//保留異常信息方法2
Exception newex = new Exception("新的異常信息!");
newex.initCause(e);
throw newex;
}
}
}
當我們不做處理時,得到的異常信息如下:
使用 方法1或方法2 來保留異常信息結果如下: