導語
異常指的是在程序運行過程中發生的異常事件,通常是由硬件問題或者程序設計問題所導致的。異常處理提供了處理程序運行時出現的任何意外或異常情況的方法,代替了日漸衰落的error code方法,因其分離了接收和處理錯誤代碼,增強了代碼的可讀性,方便了代碼的維護。
java中的異常
java是一門面向對象語言,其異常自然也是一種對象。
異常類層次結構圖:
在 Java 中,所有的異常都有一個共同的祖先
Throwable
(可拋出)。Throwable
指定代碼中可用異常傳播機制通過 Java 應用程序傳輸的任何問題的共性。Throwable:有兩個重要的子類:
Exception
(異常)和Error
(錯誤),二者都是 Java 異常處理的重要子類,各自都包含大量子類。Error(錯誤):是程序無法處理的錯誤,表示運行應用程序中較嚴重問題。大多數錯誤與代碼編寫者執行的操作無關,而表示代碼運行時 JVM(Java 虛擬機)出現的問題。例如,Java虛擬機運行錯誤(
Virtual MachineError
),當 JVM 不再有繼續執行操作所需的內存資源時,將出現OutOfMemoryError
。這些異常發生時,Java虛擬機(JVM)一般會選擇線程終止。Exception(異常):是程序本身可以處理的異常。
Exception
類有一個重要的子類RuntimeException
。RuntimeException
類及其子類表示“JVM 常用操作”引發的錯誤。例如,若試圖使用空值對象引用、除數為零或數組越界,則分別引發運行時異常NullPointerException
、ArithmeticException
和ArrayIndexOutOfBoundException
。
注意: 異常和錯誤的區別:異常能被程序本身可以處理,錯誤是無法處理。
異常的類型
java中的異常包括可查異常(checked exceptions)以及不可查異常(unchecked exceptions)。
可查異常(編譯器要求必須處置的異常):正確的程序在運行中,很容易出現的、情理可容的異常狀況。可查異常雖然是異常狀況,但在一定程度上它的發生是可以預計的,而且一旦發生這種異常狀況,就必須采取某種方式進行處理。除了
RuntimeException
及其子類以外,其他的Exception
類及其子類都屬于可查異常。這種異常的特點是Java編譯器會檢查它,也就是說,當程序中可能出現這類異常,要么用try-catch
語句捕獲它,要么用throws
子句聲明拋出它,否則編譯不會通過。不可查異常(編譯器不要求強制處置的異常):包括運行時異常(
RuntimeException
與其子類)和錯誤(Error
)。Exception
這種異常分兩大類運行時異常和非運行時異常(編譯異常)。程序中應當盡可能去處理這些異常。
-
運行時異常:都是
RuntimeException
類及其子類異常,如NullPointerException
、IndexOutOfBoundsException
等,這些異常是不檢查異常,程序中可以選擇捕獲處理,也可以不處理。這些異常一般是由程序邏輯錯誤引起的,程序應該從邏輯角度盡可能避免這類異常的發生。
運行時異常的特點是Java編譯器不會檢查它,也就是說,當程序中可能出現這類異常,即使沒有用try-catch
語句捕獲它,也沒有用throws
子句聲明拋出它,也會編譯通過。 -
非運行時異常 (編譯異常):是
RuntimeException
以外的異常,類型上都屬于Exception
類及其子類。從程序語法角度講是必須進行處理的異常,如果不處理,程序就不能編譯通過。如IOException
、SQLException
等以及用戶自定義的Exception
異常,一般情況下不自定義檢查異常。
java中的異常處理機制
在 Java 應用程序中,異常處理機制為:拋出異常,捕捉異常。
-
拋出異常:java使用
throw
關鍵詞拋出一個異常,一般語法如下:
throw new MyException("這是一個異常");//異常信息
-
捕獲異常: java使用
try catch finally
語句捕獲并處理異常,一般語法形式如下:
try {
// 可能會發生異常的程序代碼
} catch (Type1 id1){
// 捕獲并處置try拋出的異常類型Type1
}catch (Type2 id2){
//捕獲并處置try拋出的異常類型Type2
}finally {
}
自定義異常
自定義異常只需繼承
Exception
類即可,代碼如下:
class 異常類名 extends Exception
{
public 異常類名(String msg)
{
super(msg);
}
}
異常處理的兩種辦法
java對于異常有兩種處理方法,一種是自己捕獲并處理,一種是將異常上拋。
假設現在我們要寫一個函數,該函數會觸發3種異常 E1、E2、E3。 我們有三種處理辦法。
- 全部自己處理異常。
void function fun1(){
try {
// 可能會發生異常的程序代碼
} catch (E1 e1){
// 捕獲并處置try拋出的異常類型E1
}catch (E2 e2){
// 捕獲并處置try拋出的異常類型E2
}catch (E3 e3){
// 捕獲并處置try拋出的異常類型E3
}finally {
}
}
- 全部向上拋出。
void function fun1() throws E1 , E2 , E3 {
// 可能會發生異常的程序代碼
}
- 部分自己處理 部分向上拋出。
void function fun1() throws E2 {
try {
// 可能會發生異常的程序代碼
} catch (E1 e1){
// 捕獲并處置try拋出的異常類型E1
}catch (E3 e3){
// 捕獲并處置try拋出的異常類型E3
}finally {
}
}
我們向上拋的異常就會交給該函數的調用者進行處理,同理,該調用者也可以選擇自己處理異常,也可以選擇繼續向上拋。