天天看點

Java的異 常

<b>簡述:</b>異 常

" 異 常" 指 的 是 程 序 運 行 時 出 現 的 非 正 常 情 況。 在 用 傳 統 的 語 言 編 程 時, 程 序 員 隻 能 通 過 函 數 的 返 回 值 來 發 出 錯 誤 信 息。 這 易 于 導 緻 很 多 錯 誤, 因 為 在 很 多 情 況 下 需 要 知 道 錯 誤 産 生 的 内 部 細 節。 通 常, 用 全 局 變 量errno來 存 儲" 異 常" 的 類 型。 這 容 易 導 緻 誤 用, 因 為 一 個errno的 值 有 可 能 在 被 處 理 ?reg; 前 被 另 外 的 錯 誤 覆 蓋 掉。 即 使 最 優 美 的C語 言 程 序, 為 了 處 理" 異 常" 情 況, 也 常 求 助 于goto語 句。 Java對" 異 常" 的 處 理 是 面 向 對 象 的。 一 個Java的Exception是 一 個 描 述" 異 常" 情 況 的 對 象。 當 出 現" 異 常" 情 況 時, 一 個Exception對 象 就 産 生 了, 并 放 到 産 生 這 個" 異 常" 的 成 員 函 數 裡。 8.1 基礎 Java的" 異 常" 處 理 是 通 過5個 關 鍵 詞 來 實 現 的:try, catch, throw, throws和finally。 用try 來 執 行 一 段 程 序, 如 果 出 現" 異 常", 系 統 抛 出(throws?copy; 一 個" 異 常", 你 可 以 通 過 它 的 類 型 來 捕 捉(catch?copy; 它, 或 最 後(finally?copy; 由 缺 省 處 理 器 來 處 理。 下 面 是" 異 常" 處 理 程 序 的 基 本 形 式: try { //程 序 塊 } catch (ExceptionType1 e) { // 對ExceptionType1的 處 理 } catch (ExceptionType2 e) { // 對ExceptionType2的 處 理 throw(e); //再 抛 出 這 個" 異 常" } finally { } 8.2 "異 常" 的 類 型 在" 異 常" 類 層 次 的 最 上 層 有 一 個 單 獨 的 類 叫 做Throwable。 這 個 類 用 來 表 示 所 有 的" 異 常" 情 況。 每 個" 異 常" 類 型 都 是Throwable的 子 類。Throwable有 兩 個 直 接 的 子 類。 一 類 是Exception, 是 用 戶 程 序 能 夠 捕 捉 到 的" 異 常" 情 況。 我 們 将 通 過 産 生 它 的 子 類 來 創 建 自 己 的" 異 常"。 另 一 類 是Error, 它 定 義 了 那 ?copy; 通 常 無 法 捕 捉 到 的" 異 常"。 要 謹 慎 使 用Error子 類, 因 為 它 們 通 常 會 導 緻 災 難 性 的 失 敗。 在Exception中 有 一 個 子 類RuntimeException, 它 是 程 序 運 行 時 自 動 地 對 某 ?copy; 錯 誤 作 出 反 應 而 産 生 的。 8.3 不 捕 捉" 異 常" " 異 常" 對 象 是Java在 運 行 時 對 某 ?copy;" 異 常" 情 況 作 出 反 應 而 産 生 的。 例 如, 下 面 這 個 小 程 序 包 含 一 個 整 數 被0除 的" 異 常"。 class Exc0 { public static void main(String args[]) { int d = 0; int a = 42/d; } } 當Java執 行 這 個 除 法 時, 由 于 分 母 是0, 就 會 構 造 一 個" 異 常" 對 象 來 使 程 序 停 下 來 并 處 理 這 個 錯 誤 情 況, 在 運 行 時" 抛 出"(throw?copy; 這 個" 異 常"。 說" 抛 出" 是 因 為 它 象 一 個 滾 燙 的 馬 鈴 薯, 你 必 須 把 它 抓 住 并 立 即 處 理。 程 序 流 将 會 在 除 号 操 作 符 處 被 打 斷, 然 後 檢 查 當 前 的 調 用 堆 棧 來 查 找" 異 常"。 一 個" 異 常" 處 理 器 是 用 來 立 即 處 理" 異 常" 情 況 的。 在 這 個 例 子 裡, 我 們 沒 有 編 一 個" 異 常" 處 理 器, 所 以 缺 省 的 處 理 器 就 發 揮 作 用 了。 缺 省 的 處 理 器 打 印Exception的 字 符 ?reg; 值 和 發 生 " 異 常" 的 地 點。 下 面 是 我 們 的 小 例 子 的 輸 出。 C:\&gt;java Exc0 java.lang.arithmeticException: / by zero at Exc0.main(Exc0.java:4) 8.4 try與catch 通 常 我 們 希 望 自 己 來 處 理" 異 常" 并 繼 續 運 行。 可 以 用try來 指 定 一 塊 預 防 所 有" 異 常" 的 的 程 序。 緊 跟 在try程 序 後 面, 應 包 含 一 個catch子 句 來 指 定 你 想 要 捕 捉 的" 異 常" 的 類 型。 例 如, 下 面 的 例 子 是 在 前 面 的 例 子 的 基礎上 構 造 的, 但 它 包 含 一 個try程 序 塊 和 一 個catch子 句。 class exc1 { public static void main(string args[]) { try { int d = 0; int a = 42 / d; } catch (arithmeticexception e) { system.out.println("division by zero"); } } } catch子 句 的 目 标 是 解 決" 異 常" 情 況, 把 變 量 設 到 合 理 的 狀 态, 并 象 沒 有 出 錯 一 樣 繼 續 運 行。 如 果 一 個 子 程 序 不 處 理 某 個" 異 常", 則 返 到 上 一 級 處 理, 直 到 最 外 一 級。 8.5 多 個catch子 句 在 某 情 況 下, 同 一 段 程 序 可 能 産 生 不 止 一 種" 異 常" 情 況。 你 可 以 放 置 多 個catch子 句, 其 中 每 一 種" 異 常" 類 型 都 将 被 檢 查, 第 一 個 與 ?reg; 匹 配 的 就 會 被 執 行。 如 果 一 個 類 和 其 子 類 都 有 的 話, 應 把 子 類 放 在 前 面, 否 則 将 永 遠 不 會 到 達 子 類。 下 面 是 一 個 有 兩 個catch子 句 的 程 序 的 例 子。 class MultiCatch { public static void main(String args[]) { try { int a = args.length; System.out.println("a = " + a); int b = 42/a; int c[] = {1}; c[42] = 99; } catch(ArithmeticException e) { System.out.println("div by 0: " + e); } catch(ArrayIndexOutOfBoundsException e) { system.out.println("array index oob: " + e); } } } 如 果 在 程 序 運 行 時 不 跟 參 數, 将 會 引 起 一 個0做 除 數 的" 異 常", 因 為a的 值 為0。 如 果 我 們 提 ?copy; 一 個 命 令 行 參 數, 将 不 會 産 生 這 個" 異 常", 因 為a的 值 大 于0。 但 會 引 起 一 個 ArrayIndexOutOfBoundexception的" 異 常", 因 為 整 型 數 組c的 長 度 是1, 卻 給c[42]賦 值。 下 面 是 以 上 兩 種 情 況 的 運 行 結 果。 C:\&gt;java MultiCatch a = 0 div by 0: java.lang.arithmeticexception: / by zero C:\&gt;java MutiCatch 1 a = 1 array index oob: java.lang.ArrayIndexOutOfBoundsException:42 8.6 try語 句 的 嵌 套 你 可 以 在 一 個 成 員 函 數 調 用 的 外 面 寫 一 個try語 句, 在 這 個 成 員 函 數 内 部, 寫 另 一 個try語 句 保 護 其 他 代 碼。 每 當 遇 到 一 個try語 句," 異 常" 的 框 架 就 放 到 堆 棧 上 面, 直 到 所 有 的try語 句 都 完 成。 如 果 下 一 級 的try語 句 沒 有 對 某 種" 異 常" 進 行 處 理, 堆 棧 就 會 展 開, 直 到 遇 到 有 處 理 這 種" 異 常" 的try語 句。 下 面 是 一 個try語 句 嵌 套 的 例 子。 class MultiNest { static void procedure() { try { int c[] = { 1 }: c[42] = 99; } catch(ArrayIndexOutOfBoundsexception e) { System.out.println("array index oob: " + e); } } public static void main(String args[]) { try { int a = args.length; system.out.println("a = " + a); int b = 42/a; procedure(); } catch(arithmeticException e) { System.out.println("div by 0: " + e); } } } 成 員 函 數procedure裡 有 自 己 的try/catch控 制, 所 以main不 用 去 處 理 ArrayIndexOutOfBoundsException。 8.7 throw語 句 throw語 句 用 來 明 确 地 抛 出 一 個" 異 常"。 首 先, 你 必 須 得 到 一 個Throwable的 實 例 的 控 制 柄, 通 過 參 數 傳 到catch子 句, 或 者 用new操 作 符 來 創 建 一 個。 下 面 是throw語 句 的 通 常 形 式。 throw ThrowableInstance; 程 序 會 在throw語 句 後 立 即 終 止, 它 後 面 的 語 句 執 行 不 到, 然 後 在 包 含 它 的 所 有try塊 中 從 裡 向 外 尋 找 含 有 與 其 匹 配 的catch子 句 的try塊。 下 面 是 一 個 含 有throw語 句 的 例 子。 class ThrowDemo { static void demoproc() { try { throw new NullPointerException("de3mo"); } catch(NullPointerException e) { System.out.println("caught inside demoproc"); throw e; } } public static void main(String args[]) { try { demoproc(); } catch(NullPointerException e) { system.out.println("recaught: " + e); } } } 8.8 throws語 句 throws用 來 标 明 一 個 成 員 函 數 可 能 抛 出 的 各 種" 異 常"。 對 大 多 數Exception子 類 來 說,Java 編 譯 器 會 強 迫 你 聲 明 在 一 個 成 員 函 數 中 抛 出 的" 異 常" 的 類 型。 如 果" 異 常" 的 類 型 是Error或 RuntimeException, 或 它 們 的 子 類, 這 個 規 則 不 起 作 用, 因 為 這 ?copy; 在 程 序 的 正 常 部 分 中 是 不 期 待 出 現 的。 如 果 你 想 明 确 地 抛 出 一 個RuntimeException, 你 必 須 用throws語 句 來 聲 明 它 的 類 型。 這 就 重 新 定 義 了 成 員 函 數 的 定 義 語 法: type method-name(arg-list) throws exception-list { } 下 面 是 一 段 程 序, 它 抛 出 了 一 個" 異 常", 但 既 沒 有 捕 捉 它, 也 沒 有 用throws來 聲 明。 這 在 編 譯 時 将 不 會 通 過。 class ThrowsDemo1 { static void procedure( ) [ System.out.println("inside procedure"); throw new IllegalAccessException("demo"); } public static void main(String args[]) { procedure( ); } } 為 了 讓 這 個 例 子 編 譯 過 去, 我 們 需 要 聲 明 成 員 函 數procedure抛 出 了IllegalAccessException, 并 且 在 調 用 它 的 成 員 函 數main裡 捕 捉 它。 下 面 是 正 确 的 例 子: class ThrowsDemo { static void procedure( ) throws IllegalAccessException { System.out.println("inside procedure"); throw new IllegalAccessException("demo"); } public static void main(String args[]) { try { procedure( ); } catch (IllegalAccessException e) { System.out.println("caught " + e); } } } 下 面 是 輸 出 結 果: C:\&gt;java ThrowsDemo inside procedure caught java.lang.IllegalAccessException: demo 8.9 finally 當 一 個" 異 常" 被 抛 出 時, 程 序 的 執 行 就 不 再 是 線 性 的, 跳 過 某 ?copy; 行, 甚 至 會 由 于 沒 有 與 ?reg; 匹 配 的catch子 句 而 過 早 地 返 回。 有 時 确 保 一 段 代 碼 不 管 發 生 什 麼" 異 常" 都 被 執 行 到 是 必 要 的, 關 鍵 詞finally就 是 用 來 标 識 這 樣 一 段 代 碼 的。 即 使 你 沒 有catch子 句,finally程 序 塊 也 會 在 執 行 try程 序 塊 後 的 程 序 ?reg; 前 執 行。 每 個try語 句 都 需 要 至 少 一 個 與 ?reg; 相 配 的catch子 句 或finally子 句。 一 個 成 員 函 數 返 回 到 調 用 它 的 成 員 函 數, 或 者 通 過 一 個 沒 捕 捉 到 的" 異 常", 或 者 通 過 一 個 明 确 的return語 句,finally子 句 總 是 恰 好 在 成 員 函 數 返 回 前 執 行。 下 面 是 一 個 例 子, 它 有 幾 個 成 員 函 數, 每 個 成 員 函 數 用 不 同 的 途 徑 退 出, 但 執 行 了finally子 句。 class FinallyDemo { static void procA( ) { try { System.out.println("inside procA"); throw new RuntimeException("demo"); } finally { System.out.println("procA's finally"); } } static void procB( ) { try { System.out.println("inside procB"); return; } finally { System.out.println("procB's finally"); } } public static void main(String args[]) { try { procA( ); } catch (Exception e); procB( ); } } 下 面 是 這 個 例 子 的 運 行 結 果: C:\&gt;java FinallyDemo inside procA procA's finally inside procB procB's finally 本 章 小 結 1. " 異 常" 指 的 是 程 序 運 行 時 出 現 的 非 正 常 情 況。 2. 在" 異 常" 類 層 次 的 最 上 層 的 類 叫Throwable, 它 有 兩 個 直 接 的 子 類:Exception和Error。 3. Java的" 異 常" 處 理 通 過5個 關 鍵 詞 來 實 現:try,catch,throw,throws和finally。