面向对象的例外处理
什 么 是 例 外 、 例 外 處 理
例 外 就 是 在 正 常 情 況 以 外 的 事 件 。 Java 之 中 的 例 外 是 指 程 序 運(yùn) 行 中 發(fā) 生 的 異 常 事 件 , 這 些 異 常事 件 將 阻 止 程 序 的 正 常 運(yùn) 行 。 比 如 出 現(xiàn) 了 數(shù) 組 越 界 、 用戶 輸 入 錯(cuò) 誤 等 等 。 而 顧 名 思 義 , 例 外 處 理 就 是 對(duì) 這 些 例外 進(jìn) 行 處 理 。
所 有 的 高 級(jí) 計(jì) 算 機(jī) 編 程 語(yǔ) 言 里 都 有 判斷 是 否 出 現(xiàn) 了 例 外 的 語(yǔ) 句 , 每 個(gè) 好 的 計(jì) 算 機(jī) 程 序 都 會(huì) 有對(duì) 例 外 進(jìn) 行 處 理 的 程 序 段 。 只 不 過(guò) 在 不 同 的 計(jì) 算 機(jī) 編 程語(yǔ) 言 里 面 , 對(duì) 例 外 的 稱 呼 不 同 , 例 如 有 的 語(yǔ) 言 里 所 講 的錯(cuò) 誤 處 理 , 其 實(shí) 就 等 同 于 Java 里 面 的 例 外 處 理 。 這 就 像諸 葛 亮 先 生 有 兩 個(gè) 名 字 , 孔 明 是 他 諸 葛 亮 也 是 他 , 還 有人 稱 呼 他 為 諸 葛 先 生 … … , 只 是 稱 呼 不 同 罷 了 , 意 義 是一 樣 的 。
拋 棄 之
在 許 多 高 級(jí) 語(yǔ) 言 中 都 是 通 過(guò) 使 用 if 語(yǔ)句 來(lái) 判 斷 是 否 出 現(xiàn) 了 例 外 , 并 進(jìn) 行 處 理 的 。 Java 作 為 一個(gè) 完 全 基 于 面 向 對(duì) 象 的 語(yǔ) 言 , 例 外 處 理 也 是 采 用 面 向 對(duì)象 的 方 法 。 在 一 個(gè) 方 法 的 運(yùn) 行 過(guò) 程 中 如 果 發(fā) 生 了 例 外 ,則 這 個(gè) 方 法 將 生 成 一 個(gè) 代 表 該 例 外 的 對(duì) 象 , 并 把 它 提 交給 正 在 運(yùn) 行 這 個(gè) 方 法 的 系 統(tǒng) 。 我 們 把 這 個(gè) 過(guò) 程 稱 為 拋 棄一 個(gè) 例 外 。
就 像 拋 棄 這 個(gè) 球 一 樣 , 把 它 給 拋 掉 了。 拋 棄 一 個(gè) 例 外 的 過(guò) 程 就 和 我 們 平 時(shí) 工 作 中 碰 到 了 特 殊情 況 無(wú) 法 解 決 , 需 要 寫(xiě) 一 份 報(bào) 告 交 把 這 個(gè) 棘 手 的 問(wèn) 題 上報(bào) 上 級(jí) 主 管 部 門(mén) 一 樣 。
捕 獲 之
系 統(tǒng) 在 運(yùn) 行 的 時(shí) 候 查 找 處 理 提 交 給 它的 例 外 的 方 法 , 這 個(gè) 過(guò) 程 稱 為 捕 獲 一 個(gè) 例 外 。 這 就 和 法官 判 案 時(shí) 查 找 相 應(yīng) 的 法 律 條 文 的 過(guò) 程 是 一 樣 的 。
優(yōu) 越 性
1. 利 用 以 上 這 些 方 法 處 理 例 外 , 使 得例 外 處 理 的 程 序 代 碼 與 普 通 的 程 序 代 碼 不 再 混 為 一 體 ,減 少 了 編 程 序 的 工 作 量 , 同 時(shí) 也 增 加 了 程 序 可 讀 性 。
2. 利 用 面 向 對(duì) 象 的 方 法 來(lái) 處 理 例 外 ,可 以 對(duì) 各 種 不 同 的 例 外 事 件 進(jìn) 行 分 類 , 然 后 再 處 理 之 ,從 而 具 有 了 良 好 的 接 口 和 層 次 性 。
3. 利 用 類 的 層 次 性 既 可 以 區(qū) 分 不 同 的例 外 分 別 處 理 , 也 可 以 把 具 有 相 同 父 類 的 多 個(gè) 例 外 統(tǒng) 一處 理 , 具 有 相 當(dāng) 的 靈 活 性 。
由 以 上 幾 點(diǎn) 可 知 , Java 的 這 種 面 向 對(duì) 象的 例 外 處 理 機(jī) 制 為 那 些 具 有 動(dòng) 態(tài) 運(yùn) 行 特 性 的 復(fù) 雜 程 序 提供 了 強(qiáng) 有 力 的 控 制 方 式 。
以 上 這 些 優(yōu) 越 性 背 下 來(lái) 就 可 以 了 , 到時(shí) 候 可 以 用 來(lái) 在 孩 兒 們 面 前 炫 耀 一 下 自 己 的 知 識(shí) 淵 博 。
與 例 外 處 理 相 關(guān) 的 類
用 面 向 對(duì) 象 的 方 法 來(lái) 進(jìn) 行 例 外 處 理 首先 必 須 建 立 類 的 層 次 。 如 圖 20.1 所 示 , 類 Throwable 是 最 頂層 的 , 只 有 它 的 子 類 才 可 以 作 為 一 個(gè) 例 外 被 拋 棄 。
運(yùn) 行 時(shí) 與 非 運(yùn) 行 時(shí) 例 外?
Java 有 運(yùn) 行 時(shí) 例 外 和 非 運(yùn) 行 時(shí) 例 外 之 分。
所 謂 運(yùn) 行 時(shí) 例 外 就 是 由 系 統(tǒng) 在 Java 程 序運(yùn) 行 的 過(guò) 程 中 檢 測(cè) 到 的 例 外 , 例 如 除 零 溢 出 ( 除 數(shù) 為 零導(dǎo) 致 的 錯(cuò) 誤 ) 、 數(shù) 組 越 界 等 。 由 于 它 們 可 能 在 程 序 的 任何 位 置 發(fā) 生 , 而 且 誰(shuí) 也 無(wú) 法 在 程 序 運(yùn) 行 以 前 計(jì) 算 出 它 們會(huì) 發(fā) 生 多 少 次 , 所 以 Java 語(yǔ) 言 編 譯 器 允 許 Java 程 序 不 對(duì) 它進(jìn) 行 處 理 。
除 此 之 外 的 其 他 例 外 則 被 稱 為 非 運(yùn) 行時(shí) 例 外 。
圖 20.1 例 外 處 理 — — 類 的 層 次?
用 戶 自 己 定 義 的 例 外 都 是 非 運(yùn) 行 時(shí) 例外 。 然 而 并 非 所 有 非 運(yùn) 行 時(shí) 例 外 都 是 用 戶 自 己 定 義 的 例外 。
所 謂 用 戶 自 己 定 義 的 例 外 , 就 是 你 在編 寫(xiě) 程 序 的 時(shí) 候 在 你 的 程 序 里 面 定 義 的 那 些 例 外 , 以 便使 得 你 的 程 序 具 有 更 高 的 可 靠 性 , 不 會(huì) 輕 易 地 出 差 錯(cuò) 。
Java 編 譯 器 要 求 必 須 捕 獲 或 聲 明 所 有 的非 運(yùn) 行 時(shí) 例 外 。 對(duì) 于 用 戶 自 定 義 例 外 , 這 是 十 分 顯 然 的; 否 則 , 系 統(tǒng) 就 不 知 道 這 些 用 戶 自 定 義 的 例 外 的 特 性 。知 己 知 彼 才 能 百 戰(zhàn) 百 勝 。
簡(jiǎn) 單 的 例 外 處 理?
運(yùn) 行 時(shí) 例 外 的 處 理
先 看 看 下 面 這 兩 個(gè) 例 子 。
程 序 20.1
public class REP{
public static void main(String args[ ]) {
int AE = 1/0; // AE 等 于 1 除 以 0 , 將 導(dǎo) 致除 0 溢 出 例 外
}
}
程 序 20.2
public class REP{
public static void main(String args[ ]) {
int i = 0;
int AE = 1/i; // AE 等 于 1 除 以 i , 而 i 等于 0 , 也 將 導(dǎo) 致 除 0 溢 出
}
}?
在 程 序 20.1 和 程 序 20.2 中 都 出 現(xiàn) 了 除 數(shù)為 0 導(dǎo) 致 的 “ 除 0 溢 出 ” 例 外 , 這 屬 于 運(yùn) 行 時(shí) 例 外 。 此 時(shí), 運(yùn) 行 程 序 的 系 統(tǒng) 會(huì) 自 動(dòng) 把 生 成 的 例 外 對(duì) 象 交 給 缺 省 的( 也 就 是 默 認(rèn) 的 ) 例 外 處 理 程 序 , 在 計(jì) 算 機(jī) 屏 幕 上 顯 示出 這 個(gè) 例 外 的 內(nèi) 容 及 發(fā) 生 此 例 外 的 位 置 。 在 JDK 環(huán) 境 下 運(yùn)行 這 兩 個(gè) 例 子 程 序 。 ( 有 關(guān) JDK 開(kāi) 發(fā) 環(huán) 境 的 介 紹 請(qǐng) 參 見(jiàn) 《開(kāi) 發(fā) 環(huán) 境 》 一 章 )
程 序 20.1 的 運(yùn) 行 結(jié) 果 為 :
c:\java\exam >javac REP.java
REP.java:3: Arithmetic exception.
int AE = 1/0;
^
1 error
可 見(jiàn) , 程 序 在 編 譯 的 時(shí) 候 編 譯 器 就 指出 了 錯(cuò) 誤 。 此 程 序 不 能 通 過(guò) 編 譯 。 無(wú) 法 生 成 可 以 運(yùn) 行 的文 件 。
程 序 20.2 的 運(yùn) 行 結(jié) 果 是 :
c:\java\exam>javac REP.java
c:\java\exam>java REP
java.lang.ArithmeticException: / by zero
at REP.main(REP.java:4)
程 序 20.2 雖 然 通 過(guò) 了 編 譯 , 編 譯 器 沒(méi) 有指 出 有 錯(cuò) 誤 , 從 而 生 成 了 可 以 運(yùn) 行 的 程 序 文 件 , 但 是 該程 序 在 運(yùn) 行 時(shí) 系 統(tǒng) 指 出 出 現(xiàn) 了 例 外 。
非 運(yùn) 行 時(shí) 例 外
我 們 也 是 先 看 一 個(gè) 例 子 :
程 序 20.3
class MyE extends Exception{ // 定 義 一 個(gè) 例 外 類 MyE
private int detailA,detailB;
MyE(int a,int b){
detailA = a;
detailB = b;
}
public String toString(){
return "MyException : "+detailA+"<"+detailB;
}
}
?public class ED{ // 定 義 一 個(gè) 類 ED
static void compare(int a,int b) throws MyE {
System.out.println("***************************");
System.out.println("call compare("+a+","+b+")");
if (a< font>
? throw new MyE(a,b);
System.out.println("normal exit : "+a+"> = "+b);
}
?static void callcompare(int a,int b){
try{
compare(a,b);
} catch(MyE e){
System.out.println("Catch "+e);
}
finally{
System.out.println("return from callcompare()");
}
}
?public static void main (String args[ ]){
callcompare(10,5);
callcompare(5,5);
callcompare(5,10);
}
}
程 序 20.3 拋 棄 了 自 己 的 例 外 。 上 例 對(duì) 兩個(gè) 整 數(shù) a 和 b 進(jìn) 行 了 比 較 ( compare ) , 當(dāng) a ( = b 時(shí) 程 序 正常 運(yùn) 行 , 當(dāng) a((b 時(shí) 程 序 拋 棄 例 外 MyException 。?
?
在 JDK 里 例 20.3 的 運(yùn) 行 結(jié) 果 如 下 :
c:\java\exam>java ED
***************************
call compare(10,5)
normal exit : 10> = 5
return from callcompare()
***************************
call compare(5,5)
normal exit : 5> = 5
return from callcompare()
***************************
call compare(5,10)
Catch MyException : 5<10
return from callcompare()?
例 外 的 拋 棄 、 捕 獲 和 聲 明?
除 對(duì) 運(yùn) 行 時(shí) 例 外 可 以 不 做 處 理 外 , 例外 處 理 還 有 以 下 幾 種 方 法 :
在 Java 語(yǔ) 言 中 捕 獲 一 個(gè) 例 外 之 前 , 必 須有 一 段 Java 代 碼 生 成 一 個(gè) 例 外 對(duì) 象 并 把 它 拋 棄 。 拋 棄 例外 的 代 碼 可 以 是 你 自 己 Java 的 程 序 , JDK 中 的 某 個(gè) 類 , 或者 是 Java 運(yùn) 行 時(shí) 系 統(tǒng) 。 這 就 像 在 藍(lán) 球 場(chǎng) 上 打 球 一 樣 , 你 若想 接 到 一 個(gè) 球 , 就 必 須 有 人 先 拋 出 這 個(gè) 球 , 不 管 這 人 是中 鋒 , 還 是 后 衛(wèi) , 亦 或 是 對(duì) 方 球 員 。 同 理 , 如 同 所 有 人拋 球 都 必 須 用 手 一 樣 , 無(wú) 論 是 你 自 己 的 程 序 還 是 運(yùn) 行 時(shí)系 統(tǒng) , 都 必 須 使 用 throw 語(yǔ) 句 來(lái) 拋 棄 例 外 。
例 如 , 在 例 20.3 的 compare 方 法 中 就 使 用了 throw 語(yǔ) 句 來(lái) 拋 棄 一 個(gè) 例 外 :
? throw new MyE(a,b);
其 中 MyE 是 Exception 的 一 個(gè) 子 類 。
?
?
class MyE extends Exception{ // class MyException }
由 throw 拋 棄 的 例 外 必 須 是 Throwable 類 或 其 子類 的 對(duì) 象 。
聲 明 例 外
在 很 多 情 況 下 , 生 成 例 外 的 方 法 并 不需 要 處 理 它 , 而 是 用 throws 子 句 來(lái) 聲 明 它 , 以 向 上 傳 遞 。如 例 20.3 中
static void compare(int a,int b) throws MyE {
這 樣 就 在 compare 方 法 中 聲 明 了 例 外 MyE 。
一 個(gè) 方 法 中 也 可 以 同 時(shí) 聲 明 多 個(gè) 例 外, 只 需 throws 在 后 列 出 所 有 要 聲 明 的 例 外 即 可 。 例 如
static void Proc ( ) throws MyE , ArithmeticException{
… …
}
捕 獲 例 外
捕 獲 例 外 需 使 用 try-catch-finally 語(yǔ) 句 。
在 例 20.3 的 callcompare 方 法 中 , try 語(yǔ) 句 在 {} 中 指 定 了 一 段 代 碼 , 該 代 碼 可 能 會(huì) 拋 棄 幾 個(gè) 例 外 ; 其后 的 catch 用 于 處 理 這 些 例 外 ; finally 則 提 供 了 統(tǒng) 一 的 出口 。
?static void callcompare(int a,int b){
try{
compare(a,b);
}
catch(MyE e){
System.out.println("Catch "+e);
}
finally{
System.out.println("return from callcompare()");
}
}
?
程 序 20.4 import java.awt.*;
import java.applet.*;
class MyE extends Exception{ // class MyException
private int detailA,detailB;
MyE(int a,int b){
detailA = a;
detailB = b;
}
public String toString(){
return "MyException : "+detailA+"<"+detailB;
}
?
}
class Cons{ // 設(shè) 置 一 個(gè) 常 數(shù) , 讓 它 代 表 兩 條線 之 間 的 距 離
final int jmp = 13;
}
public class ED extends Applet{ // class Exception Demo
static void compare(int a,int b,Graphics g,int Ln,int col) throws MyE {
Cons jump = new Cons();
g.drawString("***************************",col,Ln);
g.drawString("call compare("+a+","+b+")",col,Ln+jump.jmp);
if (a< font>
throw new MyE(a,b);
g.drawString("normal exit :"+a+"> = "+b,col,Ln+2*jump.jmp);
}
static void callcompare(int a,int b,Graphics g,int Ln,int col){
Cons jump = new Cons();
try{
compare(a,b,g,Ln,col);
}
catch(MyE e){
g.drawString("Catch "+e,col,Ln+2*jump.jmp);
}
finally{
g.drawString("return from callcompare()",col,Ln+3*jump.jmp);
}
}
public void paint (Graphics g){
Cons jump = new Cons();
int Ln;
int col;
Ln = 10; col = 20;
callcompare(10,5,g,Ln,col);
Ln = Ln+5*jump.jmp;
callcompare(5,5,g,Ln,col);
Ln = Ln+5*jump.jmp;
callcompare(5,10,g,Ln,col);
}
}
程 序 20.4 是 程 序 20.3 的 Applet 形 式 , 它 的運(yùn) 行 結(jié) 果 如 圖 20.2 所 示 。
圖 20.2 程 序 20.4 的 執(zhí) 行 結(jié) 果
幾 件 值 得 注 意 的 事 情
MyException , MyArithmeticException 等 。
- Java 采 用 面 向 對(duì) 象 的 例 外 處 理 機(jī) 制 減 小 了 編 程量 , 增 加 了 靈 活 性 , 增 強(qiáng) 了 程 序 的 可 讀 性 和 可 靠 性 , 有利 于 編 寫(xiě) 具 有 動(dòng) 態(tài) 運(yùn) 行 特 性 的 復(fù) 雜 程 序 。
- 對(duì) 非 運(yùn) 行 時(shí) 例 外 必 須 捕 獲 或 聲 明 。
對(duì) 于 自 定 義 的 例 外 類 , 通 常 作 為 類 Exception 的 子 類 , 而 不 作 為 類 Error 的 子 類 。 因 為 類 Error 通 常 用 于系 統(tǒng) 內(nèi) 嚴(yán) 重 的 硬 件 錯(cuò) 誤 。 - 拋 棄 的 例 外 必 須 是 Throwable 類 或 其 子 類 的 對(duì) 象。
- 注 意 區(qū) 分 throw 和 throws 的 用 法 :
throw 用 于 拋 棄 例 外 ;
throws 用 于 聲 明 例 外 。
轉(zhuǎn)載于:https://www.cnblogs.com/liuzhuqing/archive/2010/12/13/7481212.html
總結(jié)
- 上一篇: Windows 7 SP1确实将有性能改
- 下一篇: 写在园子里的第一篇BLOG