異常概述
我們在寫程序的時候是爲了描述現實生活中的事物,那麼現實生活中的事物也會存在一些問題,問題本身也是現實生活中的一個具體事物,也可以通過java類的形式封裝成對象進行描述,java對此稱爲——異常,其實就是java對不正常情況描述後的對象體現
對於問題的劃分,分爲兩種:
嚴重問題:Error
非嚴重問題:Exception
對比現實生活,把人體疾病就可以封裝成一個對象進行描述,分爲可治癒和不可治癒,不可治癒的呢就是Error,可治癒的就是Exception,對於Error異常一般不編寫針對性的代碼進行處理,對於Exception可以編寫一些針對性的代碼進行處理,本篇文章也會圍繞着Exception進行編寫
無論是Error還是Exception都具有一些共性內容,例如不正常情況的信息,引發原因提示,向上抽取後就完成了一個基本的體系:
點此查看官方API文檔
Throwable
-Error
-Exception
作爲初學者如果看到這兩張圖片或許已經開始懷疑人生了,不要怕,我們並不會涉及到那麼多異常,本文中也只挑選一下比較常見的進行講解;
舉個栗子:可治癒疾病下的N多種疾病,這些就是N多種疾病的具體體現,java將顯示生活的很多的問題都進行了描述封裝,異常就是用面對對象的思想進行描述,然後進行了封裝
try catch
首先看下面這個栗子
class ErrorDemo
{
public static void main(String args[])
{
Demo d = new Demo();
d.div(5,0);
}
}
class Demo
{
int div(int a,int b)
{
return a/b;
}
}
執行報錯如下:
代碼裏面算式除數不爲0才能想出相除
我們這段程序引發了java虛擬機定義的異常,java虛擬機內部的異常處理機制,直接提前停止程序,我們現在需要做的是把異常處理掉
java提供了特有的語句進行處理:
//處理異常的最基本的代碼塊格式
//由三部分組成,是一個整體
try
{
//需要被檢測的代碼
}
catch(異常類 變量)
{
//處理異常的代碼,也就是處理方式
}
finally
{
//一定會執行的語句
}
瞭解了上面的異常處理語句,就可以針對上面的報錯進行分析處理了:
class ErrorDemo
{
public static void main(String args[])
{
Demo d = new Demo();
try
{
d.div(5,0);
}
catch(Exception e)
{
System.out.println("除數爲0!");
}
}
}
class Demo
{
int div(int a,int b)
{
return a/b;
}
}
問題處理細節請看下面代碼塊:
class ErrorDemo
{
public static void main(String args[])
{
//1.創建對象
Demo d = new Demo();
try//7.try檢測語句是否存在異常對象,無此try語句則使用虛擬機默認處理方式
{
//2.當d對象調用div函數的時候把5和0傳給了a和b
d.div(5,0);//6.new AritchmeticException()
//錯誤拋出後接下來的語句都不會被執行
}
catch(Exception e)//8.try檢測到來了這個對象後拋給了catch,參數用來接收傳遞過來的異常對象 ==Exception e = new ArithmeticException();
{
System.out.println("除數爲0!");//9.執行此語句,問題被處理
}
finally
{
System.out.print("以上兩個部分執行完畢後執行此內容");//10.一定會執行的語句
}
}
}
class Demo
{
//3.main函數講5和0傳入
int div(int a,int b)
{
//4.此處開始運算,引發java虛擬機識別的算術問題
return a/b; // 5.將問題變成new AritchmeticException()對象,並且拋給了調用這個功能的調用者
}
}
這裏還有一個問題,catch(Exception e)這裏的e有什麼作用呢?
更多內容可以查看下官方API,本文不多做描述了
throws
這裏介紹一下throws,首先回到上面的栗子
int div(int a,int b)
{
return a/b;
}
這個除法方法,對方傳值的參數是不確定的,可能傳的是正常的參數,也可能傳0或者其他內容,這個時候編寫功能的人就會在這個功能上添加一個標識——throws Exception
int div(int a,int b)throws Exception //在功能上通過throws聲明瞭該功能有可能會出現問題
{
return a/b;
}
編譯時提示:
加上throws後編譯會提示必須將div功能的問題進行處理,處理方式有兩種:分別是上面提示的捕捉、拋出
之前的例子我們已經使用過了捕獲,咱們這裏演示一下拋出:
class ErrorDemo
{
public static void main(String args[])throws Exception //將問題拋給java虛擬機
{
Demo d = new Demo();
d.div(5,8);
}
}
class Demo
{
int div(int a,int b)throws Exception //在功能上通過throws聲明瞭該功能有可能會出現問題
{
return a/b;
}
}
這裏的流程就是我們將問題拋給調用此內容的對象,然後又拋給了java虛擬機,然後虛擬機使用了默認的處理方式(報錯),所以我們正常的處理方式就應該進行捕捉:
class ErrorDemo
{
public static void main(String args[])//throws Exception
{
Demo d = new Demo();
try//處理問題
{
d.div(5,0);
}
catch(Exception e)
{
System.out.println(e.toString());
}
finally
{
System.out.print("以上兩個部分執行完畢後執行此內容");
}
}
}
class Demo
{
int div(int a,int b)throws Exception //拋出問題
{
return a/b;
}
}
多異常處理
我們在定義功能的時候有可能會發生不止一個問題,這就要用到我們的多異常處理,聲明異常時可以聲明更爲具體的異常,這樣處理可以更具體
請看下面的栗子:
int div(int a,int b)//ArithmeticException,ArrayIndexOutOfBoundsException
{
//參數a=4;b=0;
int arr[] = new arr[a];
arr[4]=1;//角標越界
return a/b;
}
這個代碼塊就出現了兩個問題,一個數組越界,一個除數爲0,所以這裏我們拋出了兩個異常對象,同樣,在處理時也需要針對性的處理:
lass ErrorDemo
{
public static void main(String args[])//throws Exception
{
Demo d = new Demo();
try//處理問題
{
d.div(5,0);
}
catch(ArithmeticException e)
{
System.out.println(e.toString());
System.out.println("除數爲0異常處理");
}
catch(ArrayIndexOutOfBoundsException e)
{
System.out.println(e.toString());
System.out.println("下標越界異常處理");
}
finally
{
System.out.print("以上兩個部分執行完畢後執行此內容");
}
}
}
class Demo
{
int div(int a,int b)throws ArithmeticException,ArrayIndexOutOfBoundsException
{
int arr[] = new arr[a];
arr[4]=1;//角標越界
return a/b;
}
}
這裏進行多異常處理的時候流程也跟之前抓捕一樣,只不過catch抓捕到了內容之後會做一個選擇,查看下面的catch語句是否是當前出現的異常對象,是的話則進入代碼塊處理異常,因爲多態性的關係,catch(Exception e)可以抓捕所有異常,多異常處理的話,對方聲明幾個異常就要有幾個catch塊,注意,父類異常catch塊要向下放,否則之前定義的catch塊都是無效的,不要定義多餘的catch塊,在實際運用中不要像上面的案例一樣只用一句print處理異常,一定要定義具體的處理方式
自定義異常
java本身對一些常見的異常做了一些封裝,那麼如果在我們自己做項目的過程中出現了一些特有的,java沒有描述過的異常,既然java可以根據問題進行對象封裝,那麼我們自己也可以對一些特有的問題做一些封裝,這就是——自定義異常
int div(int a,int b)
{
return a/b;
}
沒錯,又雙叒叕是這個栗子,對於除數是-1的情況,我們來自定義一個異常來描述,定義一個異常類:
class MinusException extends Exception
{
}
既然是異常,肯定要融入異常體系當中,所以繼承了Exception類,因爲java無法識別我們自己定義的異常,所以只能手動拋出:
int div(int a,int b)
{
if(b<0)
{
throw new MinusException();//通過throw關鍵字拋出自定義異常對象
}
return a/b;
}
編譯報錯如下:
當在函數內部出現了throw拋出異常對象,就必須要給出對應的處理動作:
要麼在內部try-catch處理,要麼在函數上聲明,讓調用者處理
一般情況下,函數內出現異常,函數上需要聲明:
int div(int a,int b)throws MinusException
{
if(b<0)
{
throw new MinusException();//通過throw關鍵字拋出自定義異常對象
}
return a/b;
}
編譯報錯:
異常已經拋出,現在調用方需要處理了
class ErrorDemo
{
public static void main(String args[])
{
Demo d = new Demo();
try
{
d.div(4,-2);
}
catch(MinusException e)
{
System.out.println("除數出現了負數了!");
}
}
}
class Demo
{
int div(int a,int b)throws MinusException
{
if(b<0)
{
throw new MinusException();//通過throw關鍵字拋出自定義異常對象
}
return a/b;
}
}
class MinusException extends Exception
{
}
現在我們的自定義異常就編寫完成了,但是會發現,我們的自定義異常沒有定義所屬信息,也就是說我們打印的沒有任何的異常信息,只有一個異常的名字,下面我們開始定義異常的所屬信息,因爲父類信息以及將異常信息的操作都完成了,所以子類只要在構造的時候直接將異常信息通過super傳遞給父類,就可以通過getMessage();獲取到異常信息了,除此之外我們也可以手動來定義一些方法來輸出一些異常信息
注意:自定義異常必須要繼承Exception,因爲異常類和異常對象都需要被拋出,都具備可拋性,這個性質是Throwable這個體系中獨有的特點,只有這個體系中的類和對象纔可以被throws和throw操作
throws和throw的區別
throws
- thorws使用在函數上
- throws後面跟的是異常類,可以多個,用“,”隔開
- 表示拋出異常,由該方法的調用者來處理
- throws表示出現異常的一種可能性,並不一定會發生這些異常
throw
- throw使用在函數內
- 表示拋出異常,由方法體內的語句處理
- 只能拋出一個異常對象名
- throw跟的是異常對象
- throw一定拋出了某種異常
總結
最後總結一些常見的異常類吧
算術異常類:ArithmeticExecption
空指針異常類:NullPointerException
類型強制轉換異常:ClassCastException
數組負下標異常:NegativeArrayException
數組下標越界異常:ArrayIndexOutOfBoundsException
違背安全原則異常:SecturityException
文件已結束異常:EOFException
文件未找到異常:FileNotFoundException
字符串轉換爲數字異常:NumberFormatException
操作數據庫異常:SQLException