Java筆記---異常機制
1.定義:程式在執行時出現的不正常情況
2.異常由來:把問題封裝成物件
3.問題劃分
(1)嚴重問題:Java通過Error類進行描述,對於Error一般不編寫針對性程式碼對其進行處理
(2)非嚴重問題:Java通過Exception類進行描述,可以使用針對性的處理方式進行處理。
4.無論是Error或者Exception都有一些共性內容,比如不正常情況的資訊、引發原因等,對其向上抽取,Java將其封裝成了Throwable類
5.異常的處理
try
{
需要被檢測的程式碼;
}
catch(異常類 變數)
{
處理異常的程式碼(處理方式);
}
finally
{
一定會執行的語句;
}
catch{}是用於處理異常。如果沒有catch{}就代表異常沒有被處理,如果該異常是檢測時異常,那麼必須宣告。
對捕獲到的異常常見的操作方法
String getMessage(); //獲取異常資訊
String toString(); //獲取異常名稱、異常資訊
//JVM預設的異常處理機制就是在呼叫printStackTrace方法,
//列印異常的堆疊的跟蹤資訊
void printStackTrace(); //獲取異常名稱、異常資訊、異常出現的
//位置
例項
class Demo
{
//在功能上用throws關鍵字聲明瞭該功能可能會出現問題
//宣告之後,在呼叫該函式的時候,要麼對該函式可能出現
//的異常繼續丟擲
//要麼對該可能出現異常的函式進行捕獲處理,否則會出現
//編譯錯誤,可以提高安全性
int div(int a,int b) throws Exception
{
return a/b;
}
}
class ExceptionDemo
{
public static void main(String[] args)
{
Demo d = new Demo();
try
{
int x = d.div(4,0);
System.out.println("x = " + x);
}
catch (Exception e) //Exception e = new Arithmetic()
{
System.out.println("除零了");
//獲取異常資訊
System.out.println(e.getMessage());
//獲取異常名稱 異常資訊
System.out.println(e.tostrig());
//JVM預設的異常處理機制就是在呼叫
//printStackTrace()方法,列印異常堆疊的跟蹤資訊
//異常名稱 異常資訊 異常出現的位置
e.printStackTrace();
}
System.out.println("over");
}
}
6.多異常的處理
(1)宣告異常時,建議宣告更為具體的異常,這樣可以處理的更加具體
(2)宣告有幾個異常,就對應有幾個catch塊,不要定義多餘的catch塊,如果多個catch塊中出現繼承關係,則父類異常catch塊放在最下面,建議在進行catch處理時,catch塊中一定要定義具體處理方式,不要簡單的一句e.printStackTrace(),也不要就簡單的書寫一條輸出語句。
class Demo
{
//宣告該函式可能出現多異常,包括算數異常、角標越界異常
int div(int a,int b) throws ArithmeticException,ArrayIndexOutOfBoundsException
{
int[] arr = new int[a];
System.out.println(arr[4]);
return a/b;
}
}
class ExceptionDemo
{
public static void main(String[] args)
{
Demo d = new Demo();
try
{
int x = d.div(5,0);
System.out.println("x = " + x);
}
//算數異常catch塊
catch(ArithmeticException e)
{
System.out.println("被零除了" + e.toString());
}
//角標異常catch塊
catch(ArrayIndexOutOfBoundsException e)
{
System.out.println("角標越界異常" + e.toString());
}
//父類異常catch塊要放在最下面
catch(Exception e)
{
e.printStackTrace();
}
System.out.println("over");
}
}
7.自定義異常
定義類繼承Exception或RuntimeException
1,為了讓該類具備可拋性
2,讓該類具備操作異常的共性方法
3,當要定義自定義異常的資訊時,可以使用父類已經定義好的功能,將異常資訊傳遞給父類的建構函式
class MyException extends Exception
{
MyException(String message)
{
super(message);
}
}
自定義異常:按照Java的面向物件思想,將程式中出現的特有問題進行封裝。
(1)例項
/*
如何定義異常資訊
因為父類Throwable建構函式中已經把異常資訊的操作都完成了,
所以在子類的建構函式中,只需將異常資訊通過super()語句傳遞給父類
那麼就可以直接通過getMessage()方法獲取自定義的異常資訊
*/
class FushuException extends Exception
{
private int value; //導致異常的負數值
FushuException(String message,int value)
{
//顯示呼叫父類建構函式,處理異常資訊
super(message);
this.value = value;
}
public int getValue() //返回導致異常的負數值
{
return value;
}
}
class Demo
{
//定義該函式除數不允許是負數,否則出現異常
//在函式內部出現了throw丟擲自定義異常物件,那麼需要在函式上宣告來讓呼叫者處理,
//不然就在內部進行try catch處理,否則會出現編譯錯誤
//一般情況下,函式內出現異常、函式上需要宣告
int div(int a,int b) throws FushuException
{
if(b < 0)
{
//手動通過關鍵字throw丟擲一個自定義異常物件
throw new FushuException("除數出現了負數",b);
}
return a/b;
}
}
class ExceptionDemo
{
public static void main(String[] args)
{
Demo d = new Demo();
try
{
int x = d.div(4,-1);
System.out.println("x = " + x);
}
catch (FushuException e)
{
System.out.println(e.toString());
System.out.println("出現的負數值:" + e.getValue());
}
System.out.println("over");
}
}
(2)自定義異常中,為什麼自定義類必須繼承Exception
異常體系中有一個特點,因為異常類和物件都需要被丟擲,他們都具備可拋性,這個可拋性是Throwable這個體系中的特有特點,只有這個體系中的類和物件才可以被 throws和throw關鍵字操作
8.throws和throw的區別
(1)throws:使用在函式上,後面跟的是異常類,可以跟多個,用逗號隔開
(2)throw:使用在函式內,後面跟的是異常物件
9.RuntimeException
Exception中有一個特殊的子類異常RuntimeException(執行時異常),如果在函式內通過throw丟擲該類及該類子類異常物件,則函式上可以不用宣告,編譯時一樣通過。如果在函式上通過throws聲明瞭該類及其子類異常,呼叫者可以不用處理,編譯一樣通過。
注意:之所以不用在函式上宣告,是因為不需要讓呼叫者處理。當異常發生的時候,希望程式停止,因為在執行時出現了無法繼續運算的情況,希望程式停止後,由程式設計師對程式碼進行修正。
自定義異常時:如果該異常的發生,無法在繼續進行運算,就讓自定義異常繼承RuntimeException
9.異常分兩種
(1)編譯時被檢測的異常
該異常在編譯時,如果沒有被處理(沒有丟擲也沒有try),則編譯失敗。該異常被標識,代表可以被處理。
(2)編譯時不被檢測的異常(執行時異常、RuntimeException類以及其子類)
在編譯時,不需要處理,編譯器不檢查。該異常發生時,建議不處理,讓程式停止,需要對程式碼就行修正。
10.應用例項
class NoPlanException extends Exception //無法上課的異常
{
NoPlanException(String message)
{
super(message);
}
}
//電腦藍屏異常
class lanPingException extends Exception
{
lanPingException(String message)
{
super(message);
}
}
//電腦冒煙異常
class maoYanException extends Exception
{
maoYanException(String message)
{
super(message);
}
}
class Computer
{
private int statc = 3; //狀態值為1,表示電腦正常
public void run() throws lanPingException,maoYanException
{
if(statc == 2) //狀態值為2,表示電腦藍屏
{
throw new lanPingException("電腦藍屏了");
}
if(statc == 3) //狀態值為3,表示電腦冒煙
{
throw new maoYanException("電腦冒煙了");
}
System.out.println("電腦執行");
}
public void reset() //電腦重啟
{
statc = 1;
System.out.println("電腦重啟");
}
}
class Teacher
{
private String name;
private Computer cmpt;
Teacher(String name)
{
this.name = name;
cmpt = new Computer();
}
public void jiangke() throws NoPlanException
{
try
{
cmpt.run();
}
catch (lanPingException le)
{
System.out.println(le.toString());
cmpt.reset(); //電腦重啟
}
catch (maoYanException me)
{
throw new NoPlanException("上課無法繼續" + me.getMessage());
}
System.out.println("講課");
}
}
class ExceptionDemo
{
public static void main(String[] args)
{
Teacher t = new Teacher("小李");
try
{
t.jiangke();
}
catch (NoPlanException e)
{
System.out.println(e.toString());
System.out.println("換個老師或放假");
}
}
}
11.finally程式碼塊
(1)定義一定執行的程式碼,通常用於關閉資源的程式碼,因為資源必須釋放。
(2)finally{}只有一種情況不會執行,當執行到System.exit(0)時,finally不會執行。
下面異常處理格式也是允許的
try
{}
final
{
//關閉資源
}
12.異常在子父類中覆蓋的體現
(1)子類在覆蓋父類時,如果父類的方法丟擲異常,那麼子類的覆蓋方法,只能丟擲父類的異常或者該異常的子類,或者不拋異常
(2)如果父類方法丟擲多個異常,那麼子類在覆蓋方法時,只能丟擲父類異常的子集
(3)如果父類和介面的方法中沒有異常丟擲,那麼子類在覆蓋方法時,也不可以丟擲異常,如果子類方法中發生了異常,則必須在子類方法中進行try處理,絕對不能拋
13.異常的好處
(1)將問題封裝成物件
(2)將正常流程程式碼和問題程式碼相分離,方便於閱讀
14.異常的處理原則
1,處理方式有兩種,try或者throws
2,呼叫到有丟擲異常的功能時,丟擲幾個就處理幾個
3,多個catch,父類中的catch要放在最下面,否則編譯失敗
4,catch內需要定義針對性的處理方式,不要簡單的定義
printStackTrace、輸出語句,也不要不寫
當捕獲到的異常,本功能處理不了的時候,可以繼續在catch
中丟擲
try
{
throw new AException();
}
catch(AException e)
{
throw BException;
}
如果該異常處理不了,但並不屬於該功能出現的異常,可以將異常轉換後,再丟擲和該功能相關的異常
或者異常可以處理,但需要將異常產生的和本功能相關的問題提供出去,讓呼叫者知道,並處理。也可以將捕獲異常處理後,轉換新的異常。
try
{
throw new AException();
}
catch(AException e)
{
處理AException異常
//丟擲AException異常產生的和本功能相關的問題
throw new BException();
}