JAVA中的異常類都繼承自Throwable類,也就是說,這是異常類的根。Throwable類擴展了兩個類Error類和Exception類,Exception類又擴展了一個RuntimeException類。以下圖:javascript
通常來講,出現RuntimeException異常表示的是代碼不合理而出現的問題。php
所以,在自定義異常類型時,大多數都直接繼承Exception類,偶爾可能繼承RuntimeException類,更偶爾的可能會繼承這些類的某些子類。css
使用try-catch結構捕捉異常,並設置捕捉到後的處理方式。還能夠加上finally結構,這是可選結構,但卻表示try結構中必須會被執行的部分。html
如下是try-catch-finally結構和處理過程的分析。java
try {
// 待捕捉測試的代碼1
// 待捕捉測試的代碼2 (假設此爲異常代碼,將拋出名爲異常名2的異常)
// 待捕捉測試的代碼3
} catch (異常名1 對象名e) {
// 捕捉到異常名1的異常後,該作的處理代碼4
} catch (異常名2 對象名e) {
// 捕捉到異常名2的異常後,該作的處理代碼5
} ... {
//...
} finally {
//必定會執行的代碼6
}
//try結構外的代碼7
前提假設,在各代碼中沒有return子句。執行過程爲:首先代碼1正常執行,到代碼2處拋出異常名2的異常,經過異常名匹配,將選擇第二個catch結構,因而將異常2封裝到對象名e中,並執行代碼5處理異常。catch部分處理完後,還有最後處理段finally,因而執行代碼6。出了finally後,還將執行代碼7。nginx
注意,當代碼2出現異常後,代碼3不會執行。而finally則是不管是否真的捕捉到了異常、是否在catch段有return都會執行的代碼段。換句話說,finally段的代碼除了內部錯誤或外界影響都必定會執行。就像下面的例子中,即便catch使用了return,但finally仍是會執行,只不過這個catch終止了try結構外的代碼。git
例如,除數爲0時會拋出ArithmeticException異常。try-catch捕捉它:github
public class TEx {
public static void main(String[] args) {
try {
System.out.println("[start]");
System.out.println(2/0);
System.out.println("[end]");
} catch (ArithmeticException e) {
System.out.println("[Catching]: " + e);
return;
} finally {
System.out.println("[Finally]");
}
System.out.println("[out of try-catch]");
}
}
在finally段中還能夠繼續try-catch-finally,防止該段落的代碼再次拋出異常。web
public class TEx {
public static void main(String[] args) {
try {
System.out.println("[start]");
System.out.println(2/0);
System.out.println("[end]");
} catch (ArithmeticException e) {
System.out.println("[Catching]: " + e);
return;
} finally {
try {
System.out.println("[Finally-try-start]");
System.out.println(3/0);
} catch (ArithmeticException e) {
System.out.println("[Finally-Catching]: " + e);
}
}
System.out.println("[out of try-catch]");
}
}
java中的異常都會封裝到對象中。異常對象中有幾個方法:django
throw關鍵字用於在某個語句處拋出一個異常,只要執行到這個語句就表示一定拋出異常。
throws關鍵字用於在方法處拋出一個或多個異常,這表示執行這個方法可能會拋出異常。
throw OBJECT;
throw new EXCEPTION("Message");
method() throws EXCEPTION1[,EXCEPTION2...] {}
對於Exception類(非RuntimeException)的異常即已檢查異常類,在調用時要麼進行捕捉,要麼繼續向上級拋出。這類錯誤產生和處理的過程爲:
如下是拋出異常的一個簡單示例,拋出的是ArithmeticException異常,由於是RuntimeException類異常,所以從方法體內部throw拋出後,無需在方法定義處使用throws繼續拋出。
public class EX {
void f(int n) { // 或void f(int n) throws ArithmeticException {}
if (n == 0) {
throw new ArithmeticException("hello Exception!");
} else {
System.out.println("right!");
}
}
public static void main(String[] args) {
EX m = new EX();
m.f(1);
m.f(0); // throw Exception
}
}
執行結果:
right!
Exception in thread "main" java.lang.ArithmeticException: hello Exception! //異常的信息
at EX.f(EX.java:4) //真實產生異常的地方
at EX.main(EX.java:13) //調用產生異常的地方
因此,對於RuntimeException類異常來講,是否使用throws關鍵字並沒有影響。通常來講,Exception類異常但非RuntimeException才須要使用throws關鍵字,由於Exception類異常必需要被捕獲並處理,而RuntimeException異常則無所謂。
例如將上面的ArimeticException改成FileNotFoundException,前者爲Runtime類異常,然後者爲Exception但非Runtime類異常,所以使用throw拋出後,必須在定義方法處也使用throws拋出錯誤。這一過程是"向上級拋出"的過程:"方法體內部拋出異常-->拋給方法自己"。
void f(int n) throws FileNotFoundException {
if (n == 0) {
throw new FileNotFoundException("hello Exception!"); //throw a new yichang duixiang
} else {
System.out.println("right!");
}
}
若是不使用throws關鍵字拋出錯誤,則將報錯:
EX.java:6: 錯誤: 未報告的異常錯誤FileNotFoundException; 必須對其進行捕獲或聲明以便拋出
throw new FileNotFoundException("hello Exception!"); //throw a new yichang duixiang
從方法f()拋出向上拋出給調用者後,調用者要麼使用try-catch捕捉,要麼繼續向上拋出,不然報錯。例如捕捉
import java.io.*;
public class EX {
void f(int n) throws FileNotFoundException {
if (n == 0) {
throw new FileNotFoundException("hello Exception!");
} else {
System.out.println("right!");
}
}
public static void main(String[] args) {
try {
EX m = new EX();
m.f(0);
} catch (FileNotFoundException e) {
System.out.println(e);
}
System.out.println("out of try-catch");
}
}
若是不捕捉,則能夠繼續在方法處向上拋出:
public static void main(String[] args) throws FileNotFoundException {
EX m = new EX();
m.f(0);
}
throw能夠同時定義可能拋出的多種異常,儘管這些異常存在繼承關係。這時在捕捉異常時,應該先捕捉子類,再捕捉父類。
例如FileNotFoundException是IOException的子類,能夠同時:
throws FileNotFoundException,IOException
捕捉時應先捕捉FileNotFoundException,再IOException。
try {
...
} catch (FileNotFoundException e) {
...
} catch (IOException e) {
...
}
在重寫有throws子句的方法時,須要注意:
因此下面的定義中,前子類1-3重寫和子類5-7都是有效的,但子類4重寫是錯誤的。
父類:method() throws IOException {} 子類1:method() throws {} 子類2:method() throws IOException {} 子類3:method() throws FileNotFoundException {} 子類4:method() throws Exception {} 子類5:method() throws RuntimeException {} 子類6:method() throws IOException,RuntimeException {} 子類7:method() throws IOException,ArithmeticException {}
異常是類,當產生異常時會構建此類的異常對象。
自定義異常時須要考慮異常類的構造方法是否接參數,參數須要如何處理實現怎樣的邏輯。
自定義的異常通常都從Exception繼承。
例以下面定義了一個銀行卡存、取錢時的程序,其中自定義了一個Exception類錯誤。
// User Define Exception
class OverDrawException extends Exception {
private double amount;
public OverDrawException(double amount) {
this.amount = amount;
}
public OverDrawException(String message) {
super(message);
}
public double getAmount() {
return amount;
}
}
// Card class
class Card {
//cardNum:卡號,balance:餘額
private String cardNum;
private double balance;
Card(String n,double b) {
this.cardNum = n;
this.balance = b;
}
//方法:存錢
public void cunQian(double n) {
balance += n;
}
//方法:取錢
public void quQian(double n) throws OverDrawException {
if (n <= this.balance) {
balance -= n;
} else {
double need = n - balance;
throw new OverDrawException(need);
}
}
//方法:返回餘額
public double getBalance() {
return this.balance;
}
}
public class SuanZhang {
public static void main(String [] args) {
try {
Card card = new Card("62202",300);
System.out.println("卡里餘額:" + card.getBalance());
//存錢
card.cunQian(200);
System.out.println("餘額:" + card.getBalance());
//取錢
card.quQian(600);
System.out.println("餘額:" + card.getBalance());
} catch (OverDrawException e) {
System.out.println(e);
System.out.println("抱歉!您的餘額不足,缺乏:" + e.getAmount());
}
}
}
注:若您以爲這篇文章還不錯請點擊右下角推薦,您的支持能激發做者更大的寫做熱情,很是感謝!