Presentation is loading. Please wait.

Presentation is loading. Please wait.

第 14 章 例外處理.

Similar presentations


Presentation on theme: "第 14 章 例外處理."— Presentation transcript:

1 第 14 章 例外處理

2 本章提要 14-1 甚麼是例外? 14-2 try/catch/finally 敘述 14-3 抛出例外 14-4 自訂例外類別
14-5 綜合演練

3 前言 在整個程式的生命週期中, 難免會發生一些問題或錯誤, 大概可分為以下幾類:
編譯時期錯誤:這是在程式開發過程中所發生的, 例如初學者最常遇到的語法錯誤就屬於其中一。像是寫程式時忘了在敘述後面加分號、變數名稱打錯等等, 如此一來在編譯程式時就無法編譯成功, 因此稱之為編譯時期錯誤 (compiler-time error)。

4 前言 邏輯錯誤:這種錯誤是指程式雖能編譯成功、也能正常執行, 但執行的結果卻不是我們所預期的。
換言之是程式的邏輯有問題所產生的錯誤, 例如您要寫一個程式計算球體體積, 但將計算公式轉成程式的形式時, 不小心打錯了, 導致計算結果不正確, 這就是一種邏輯錯誤。

5 前言 執行時期錯誤:此錯誤也是在程式編譯成功後, 於執行階段發生的錯誤, 但執行時期錯誤 (run-time error) 是指程式本身邏輯沒有問題, 但在執行時發生當初設計程式時, 未預期的狀況, 導致程式無法正常執行的情形。 舉例來說, 如果程式中有除法運算, 但用來當除數的整數變數其值為 0 (可能是使用者輸入錯誤), 就會使程式發生除以 0 的錯誤。

6 前言 本章要介紹的例外處理, 就是要處理執行時期錯誤, 讓我們的程式即使遇到突發狀況時, 也能執行完成。

7 14-1 甚麼是例外? 簡單的說, 程式執行時期, 所發生的不可預期錯誤就可稱為例外 (Exception)。發生例外時, Java 程式將會不正常中止, 輕則讓使用者覺得程式有問題、重則導致使用者的資料毀損/ 喪失。為了讓 Java 程式設計人員能設計出安全可靠 (robust) 的程式, 不會因例外發生, 程式就什麼事都不能做, 因此 Java 語言特別內建了例外處理的功能。

8 有狀況:引發例外 在第二章曾介紹過, Java 程式是在 Java 虛擬機器 (JVM) 中執行的。在預設的情況下, 當程式執行時發生例外, JVM 就會攔截此例外狀況, 並拋出 (throw) 此例外事件。

9 例外案例之一:使用者輸入錯誤 使用者輸入非程式預期資料, 而導致例外, 是典型的例外案例。
在前幾章我們都有使用到由鍵盤取得使用者輸入的範例程式, 而只要我們故意輸入非程式所需的資料, 就會發生例外。 例如下面這個第 6 章的畫三角形範例:

10 例外案例之一:使用者輸入錯誤

11 例外案例之一:使用者輸入錯誤

12 例外案例之一:使用者輸入錯誤

13 例外案例之一:使用者輸入錯誤 由於第 13 行呼叫的 Integer.parseInt() 方法只能解讀以數字構成的字串, 而我們故意輸入文字或是有小數點的數字, 就會導致程式無法解讀, 而引發例外 (另一種說法是:拋出例外)。 此時 Java 會顯示一連串例外的相關訊息, 並中止程式執行 (另一說法是執行緒被終止, 關於執行緒請見下一章), 因此第 15 行以下的程式也不會執行到。

14 例外案例之一:使用者輸入錯誤 在例外訊息中, 可看到例外所屬的 『例外類別』:

15 例外案例之二:程式設計不當 另一種可能引發例外的情況是程式設計不當, 例如在第 8 章介紹陣列時提過, 當程式中使用的元素索引碼超出陣列範圍, 就會產生例外:

16 例外案例之二:程式設計不當

17 例外案例之二:程式設計不當 從執行結果我們可以看到, 當程式執行到 i 的值等於 4 的時候, 由於 4 已超出陣列元素的索引範圍, 所以執行到第 8 行程式時, 存取 a[i] (相當於 a[4]) 的動作就會引發例外。

18 例外案例之二:程式設計不當 同樣的, 這個範例也是在 Java 輸出一長串的訊息後, 程式就停止執行了, 因此第 10 行的敘述也不會被執行到。 這個範例所引發的例外, 所屬的類別和前一個例子也不同:

19 Java 程式處理例外狀況的方式 例外處理流程 例外類別

20 例外處理流程 當程式執行時發生了例外, Java 會拋出 (throw) 例外, 也就是將例外的相關資訊包裝在一個例外物件之中, 然後丟給目前執行的方法來處理, 此時會有兩種狀況: 如果方法中沒有處理這個例外的程式碼, 則轉向呼叫者 (呼叫該方法的上一層方法) 尋找有無處理此例外的程式碼。若一直找到最上層的 main() 都沒有處理這個例外的程式碼發生時, 該程式將會停止執行。

21 例外處理流程 若程式中有處理這個例外的程式碼, 則程式流程會跳到該處繼續執行 (詳細流程請參見下一節說明)。
以前面陣列索引碼超出範圍的例子而言, 該例外是在 main() 方法中拋出的, 所以 Java 會看 main() 中是否有處理該例外的處理程式, 以便將例外物件拋給它處理。

22 例外處理流程 不過在我們的範例程式中當然是沒有任何例外處理程式, 而 main() 又是最上層的方法 (畢竟程式是由它開始執行的), 所以這個例外只好由 Java 自己來處理, 而它的處理方式很簡單, 就是印出一段有關該例外的訊息, 並終止程式的執行, 由前面的執行結果即可印證。

23 例外處理流程 如果希望例外發生時, 程式不會莫名其妙的停止執行, 就必須加入適當的例外處理程式。以陣列索引碼超出範圍為例, 我們必需在 main() 方法中撰寫處理相關的例外物件, 此物件所屬的類別就是出現在錯誤訊息中的 ArrayIndex OutOfBoundsException。

24 例外處理流程 而處理這類例外的相關程式碼, 在 Java 中通常稱之為 『捕捉』 (catch) ArrayIndexOutOfBoundsException 例外的程式。

25 例外類別 在 Java 中, 所有拋出的例外都是以 Throwable 類別及其衍生類別所建立的物件來表示, 像 NumberFormatException、ArrayIndexOutOfBoundsException 都是其衍生類別。 Throwable 類別有兩個子類別:Error 和Exception 分別代表兩大類的 Java 例外, 而這兩個類別之下又各有許多子類別和衍生類別, 分別代表不同類型的例外。

26 例外類別 Error 類別:此類別及其衍生類別代表的是嚴重的錯誤, 例如系統資源不足, 導致程式無法執行、或是 JVM 本身發生錯誤。
由於此類錯誤通常也是我們無法處理的, 所以一般我們不會在程式中捕捉此類的例外物件。

27 例外類別 Exception 類別:此類別及其衍生類別就是代表一般的例外, 也是一般撰寫錯誤處理程式所會捕捉的類別。
Exception 類別之下則有多個子類別, 但在本章中我們將重點放在 RuntimeException 這個子類別。

28 例外類別

29 例外類別 顧名思義, RuntimeException 類別代表的就是『執行時的例外』。
此類別下有多個子類別和衍生類別分別代表不同類型的執行時期例外。 例如前面提過的, 在程式中指定超過範圍的索引碼時, 就會引發 ArrayIndexOut OfBoundsException 類別的例外。 此類別是 RuntimeException的孫類別, 其父類別是 IndexOutOfBoundsException。

30 例外類別 另一種我們有時會遇到的例外, 則是RuntimeException 的另一個子類別 ArithmeticException 的例外物件, 當程式中做數學運算時發生錯誤情況 (例如前面提過的除以 0), 就會引發這個例外。 接下來我們就來看要如何用 Java 程式捕捉這類例外。

31 14-2 try/catch/finally 敘述
在 Java 程式中撰寫例外處理程式, 可使用 try、catch、finally 三個敘述。 但以最簡單的捕捉例外程式, 只需用到 try 和 catch 敘述即可。

32 捕捉例外狀況 try 和 catch 敘述的意思很簡單, 當我們要執行一段有可能引發例外的程式, 我們就將它放在 try 區塊中, 同時用 catch 敘述來捕捉可能被拋出的例外物件, 並撰寫相關的處理程式。 其結構如下:

33 捕捉例外狀況

34 捕捉例外狀況 try 是嘗試的意思, 所以上列的結構就像是『嘗試執行一段可能引發例外的敘述』, 如果的則發生例外時, 就由捕捉 (catch) 該例外的區塊來處理。

35 捕捉例外狀況

36 捕捉例外狀況 舉個最簡單的例子, 若要捕捉之前所提的 ArrayIndexOutOfBoundsException 例外, 可用如下範例的 try/catch 段落來處理:

37 捕捉例外狀況

38 捕捉例外狀況

39 捕捉例外狀況 第 7〜17 行就是整個 try/catch 區塊。第 7〜11 行的 try 區塊, 就是單純用迴圈輸出所有的陣列元素。當迴圈變數 i 的值為 4 時, 執行第 10 行程式就會引發例外。 第 11〜17 行就是捕捉超出陣列範圍例外的 catch 區塊。第 15 行程式直接輸出例外物件 e 的內容。

40 捕捉例外狀況 不管有沒有發生 ArrayIndexOutOfBoundsException 例外, 都會執行到第 19 行的程式。
如果是在撰寫商用程式, 隨便顯示一行例外訊息, 對使用者來說並不友善, 因為使用者可能根本不懂 Java 程式語言, 根本不瞭解什麼是『例外』;或是不能完全明白為什麼發生錯誤。

41 捕捉例外狀況 此時若能讓程式顯示更多的相關資訊, 可幫助使用者瞭解問題所在, 例如需要使用者輸入資料的應用程式, 能回應使用者可能因為輸入什麼樣的錯誤資料, 導致程式發生問題更好。 以下就是在 catch 區塊中顯示與例外相關訊息的範例。

42 捕捉例外狀況

43 捕捉例外狀況

44 捕捉例外狀況

45 捕捉例外狀況 這個範例程式內建一個整數陣列, 並請使用者自行選擇要看陣列中的哪一個數字。
如果使用者指定的數字超出範圍, 就會引發 ArrayIndexOutOf BoundsException 的例外, 在 catch 區塊中, 會顯示這個程式只有 5 個數字, 並告知使用者指定的數字超出範圍。

46 捕捉多個例外 如果程式中雖有 try/catch 敘述捕捉特定的例外, 但在執行時發生了我們未捕捉的例外, 會發生什麼樣的狀況呢?很簡單, 就和我們沒寫任何 try/catch 敘述一樣, Java 會找不到處理這個例外的程式, 因此程式會直接結束執行。 我們直接用剛剛的 CatchAndShowInfo.java 來示範:

47 捕捉多個例外

48 捕捉多個例外 如以上執行結果所示, 雖然程式中有捕捉 ArrayIndexOutOfBoundsException, 但只要使用者輸入整數以外的內容, 就會使 Integer.parseInt() 方法因無法解譯而拋出 NumberFormatException 例外, 由於程式未捕捉此例外, 因而導致程式意外結束。

49 捕捉多個例外 要用 try/catch 敘述來解決這個問題, 我們可讓程式再多捕捉一個 ArithmeticException 例外, 也就是讓程式有兩個 catch 段落。 寫法很簡單, 只要讓 2 個 catch 段落接連列在 try 區塊之後即可。例如:

50 捕捉多個例外

51 捕捉多個例外 請參考以下的範例程式:

52 捕捉多個例外

53 捕捉多個例外

54 捕捉多個例外 第 18 行將呼叫 Integer.parseInt() 方法的敘述移到 try 區塊中, 以便程式能捕捉此方法可能拋出的例外。 第 26 捕捉 NumberFormatException 例外, 並在第 27 行顯示錯誤訊息。

55 捕捉多個例外 雖然我們可以用多個 catch 敘述來捕捉不同類型的例外, 但若可能發生的例外種類較多, 那要加好幾個 catch 敘述也有些麻煩, 而且也難保不會有所遺漏。在此情況下, 可考慮捕捉『上層』的例外類別。 在介紹此方法前, 我們再來對 Java 的例外處理機制做更進一步的認識。

56 自成體系的例外類別 Throwable 類別 Exception 類別 捕捉上層的例外

57 Throwable 類別 如前所述, Java 所有的例外都是以 Throwable 類別及其衍生類別所建立的物件。
不過這些方法中, 有些是用於自訂例外類別、部份則是進階的程式除錯才會用到, 我們就不深入探討。 另外 Throwable 類別也定義了兩個可傳回例外相關資訊的方法:

58 Throwable 類別 上述 2 個方法的用法, 可參考以下的範例程式:

59 Throwable 類別

60 Throwable 類別

61 Throwable 類別

62 Throwable 類別 Throwable 只有 Error 和 Exception 兩個子類別, 其中 Error 類別代表系統的嚴重錯誤, 通常不需由程式處理, 也就是說我們不需撰寫捕捉此類敘述的 catch 敘述。 而 Exception 類別下則有許多衍生類別分別代表一般寫程式時可能遇到的例外, 因此以下我們進一步介紹 Exception 類別及其衍生類別。

63 Exception 類別 Exception 類別之下的子類別種類相當多, 而各子類別下又有或多或少的不同子類別。
除了 RuntimeException 外, Exception 的子類別都是呼叫 Java 標準類別庫中特定的方法, 或是在我們程式要自己拋出類別時才會用到, 初學者大都只會用到 RuntimeException 這個子類別下的某幾個類別。

64 Exception 類別 除了我們已用過的 ArrayIndexOutOfBoundsException 和 ArithmeticException 外, 我們再介紹幾個 RuntimeException 下的子類別和孫類別。

65 Exception 類別 NullPointerException:當程式需使用一個指向物件的參照, 但該參照卻是 null 時就會引發此例外。 例如程式需要參考一個物件, 但我們提供的物件參照卻是 null, Java 就會拋出 NullPointerException 例外的物件。 NegativeArraySizeException:陣列大小為負數時, 就會引發此例外。

66 Exception 類別 NumberFormatException:當程式要將某個字串轉換成數值格式, 但該字串的內容並不符該數值格式的要求, 就會引發此例外。 在前面的範例已看過, 呼叫 Integer.parseInt() 方法要將字串轉成整數時, 若參數字串並非整數的形式, 就會引發格式不合的例外。

67 Exception 類別 StringIndexOutOfBoundsException:和 ArrayIndexOutOfBoundsException 一樣同屬 IndexOutOfBoundsException 的子類別, 當程式中存取字串中字元, 但指定的索引超出字串範圍時, 就會引發此例外。

68 Exception 類別

69 捕捉上層的例外 大致瞭解主要的例外類別繼承關係後, 我們就來看如何捕捉上層的例外類別物件。
其實方法也很簡單, 只要寫一個 catch 敘述, 並捕捉 Exception 或 RuntimeException 類別的物件即可, 例如下面這個簡單的程式:

70 捕捉上層的例外

71 捕捉上層的例外

72 捕捉上層的例外

73 捕捉上層的例外

74 捕捉上層的例外 第 28 行的 catch 敘述捕捉的是 IndexOutOfBoundsException 例外物件, 所以不管發生 ArrayIndexOutOfBoundsException 或是 StringIndexOutOfBoundsException 例外, 都會被捕捉, 並執行 29、30 行敘述輸出相關訊息。 如果把 28 行的程式改成捕捉更上層的 RuntimeException 例外物件, 或是 Exception 例外物件, 也具有相同的效果。

75 針對衍生例外類別做特別處理的寫法 在捕捉上層例外時, 如果您想針對某個子類別的例外進行處理, 可利用前面介紹過的捕捉多個例外類別的技巧:先捕捉該子類別;再捕捉上層類別。 例如假設有一段程式碼可能產生多種 Runtime Exception 衍生類別的例外, 但我們想特別對ArrayIndexOutOfBoundsException 的例外做額外處理, 可將程式寫成:

76 針對衍生例外類別做特別處理的寫法

77 針對衍生例外類別做特別處理的寫法 請注意, 上列 2 段 catch() 敘述的順序不可倒過來, 因為若寫成:

78 針對衍生例外類別做特別處理的寫法 則發生 ArrayIndexOutOfBoundsException 例外時, 由於 Java 找到第 1 個 catch 段落時, 因為 ArrayIndexOutOfBoundsException 為 RuntimeExceptione 的衍生類別, Java 就會將例外丟給它處理, 使得第 2 個 catch 段落永遠都不會被執行。

79 善後處理機制 回顧一下 Java 中發生例外時的流程, 當 try 區塊中的程式發生例外時, 會先看程式中有無對應的 catch 敘述, 有則執行該 catch 區塊的程式, 沒有就結束程式的執行。 因此若您沒有捕捉到程式可能發生的例外, 導致程式突然結束執行, 有時會有些不良的影響, 例如程式可能還沒將重要資料存檔, 導致使用者的重要資料喪失。

80 善後處理機制 為了讓程式能在發生例外後, 做一些善後處理工作, Java 提供了一個 finally 敘述。
此敘述的用法和 try/catch 類似, 我們只需將善後程式碼放在 finally 區塊, 並將此區塊放在 try/catch 之後即可形成一完整的 try/catch/finally 例外處理段落。

81 善後處理機制

82 善後處理機制

83 善後處理機制 此時程式執行 的流程如右圖:

84 善後處理機制 由於不管何種情況都會執行到 finally 區塊, 所以很適合用 finally 來做必要的善後處理, 例如嘗試儲存使用者尚未存檔的資料等。 若先前未發生例外或是發生程式有捕捉的例外, 則在執行完 finally 區塊後, 程式仍會依正常流程繼續執行;但若之前發生的是程式未捕捉的例外, 在執行完 finally 區塊後, Java 仍會顯示例外訊息並停止執行程式。

85 善後處理機制 讓我們來看以下這個例子:

86 善後處理機制

87 善後處理機制

88 善後處理機制 在第 09、10 行故意加了兩行除以零的運算, 以引發 ArithmeticException 例外, 而程式中並未捕捉此例外物件。 但當 Java 拋出此例外時, 程式仍會執行到 21 行 finally 區塊中的敘述後, 才停止執行。 也因為例外的發生, 所以第23 行的程式不會被執行。

89 善後處理機制 讀者可試一下在第 10 行程式前面加上 "//" 使其變成註解, 重新編譯、執行程式, 此時您就會發現程式引發 IndexOutOfBoundsException 例外後, 第 21、23 行的敘述都會被執行。

90 14-3 拋出例外 將例外傳遞給呼叫者 自行抛出例外

91 將例外傳遞給呼叫者 在開發 Java 程式時, 若預期程式可能會遇到自己無法處理的例外時, 我們可以選擇拋出例外, 讓上層的程式 (例如呼叫程式的程式) 去處理。 要拋出例外需使用 throw 以及 throws 敘述, throws 敘述我們也已用過很多次, 每當要從鍵盤讀入使用者輸入時, main() 方法後面就會加上 "throws IOException" 的註記, 以下說明為何 main() 方法要加上此段敘述。

92 認識 Checked/Unchecked 例外
除了根據例外類別的繼承關係將例外類別分為 Error 和 Exception 兩大類外, 還有一種分類方式, 是根據編譯器在編譯程式時, 是否會檢查程式中有沒有妥善處理該種例外:此時可將例外分成 Unchecked (不檢查) 和 Checked (會檢查) 兩種。

93 認識 Checked/Unchecked 例外
Unchecked 例外:所有屬於 Errors 或 RuntimeException 的衍生類別的例外都歸於此類, 前者是我們無法處理的例外。 而後者則是可利用適當的程式邏輯避免的例外 (例如做除法運算前先檢查除數是否為 0、存取陣列前檢查索引碼是否超出範圍)。 所以 Java 並不要求我們在程式處理此類例外, 因此稱之為編譯器『不檢查的』 (Unchecked) 例外。

94 認識 Checked/Unchecked 例外
Checked 例外:除了 RuntimeException 以外, 所有 Exception 的衍生類別都屬於此類。 Java 語言規定, 所有的方法都必須處理這類例外, 因此稱之為編譯器『會檢查的』 (Checked) 例外, 如果我們不處理的話, 在編譯程式時就會出現錯誤, 無法編譯成功。

95 認識 Checked/Unchecked 例外
以前幾章我們在 main() 方法中取得鍵盤輸入的程式為例, 由 BufferedReader 類別的 readLine() 方法的原型宣告可發現它可能會拋出 IOException 例外。 而 IOException 正屬於 Checked 例外之一, 因此使用到這個方法時, 我們就必須在程式中『處理』這個例外, 處理方式有二:

96 認識 Checked/Unchecked 例外
自行用 try/catch 敘述來處理:以使用 readLine() 方法為例, 我們必須用 try 段落包住執行 readLine() 方法的敘述, 然後用 catch 敘述來處理 IOException 例外。 但初學 Java 時, 暫時不必做此種複雜的處理, 因此可採第 2 種方式。

97 認識 Checked/Unchecked 例外
將 Checked 例外拋給上層的呼叫者處理:當我們在 main() 方法後面加上 "throws IOException" 的宣告, 就表示 main() 方法可能會引發 IOException 例外, 而且它會將此例外拋給上層的呼叫者 (在此為 JVM) 來處理。這也是一般程式會採用的方式。 另一方面, 在撰寫自訂的方法時, 若此方法會拋出例外, 必須在方法宣告中用 "throws" 敘述, 註明所有可能拋出的例外類別種類。

98 認識 Checked/Unchecked 例外
如果我們不將 main() 方法宣告為 "throws IOException" 的話, 就必須用 try/catch 的方式來處理 BufferedReader 類別的 readLine() 方法, 或其它會拋出 Checked 例外的方法。 例如我們可將先前的範例改寫如下:

99 認識 Checked/Unchecked 例外

100 認識 Checked/Unchecked 例外

101 認識 Checked/Unchecked 例外

102 認識 Checked/Unchecked 例外
原本使用 readLine() 這類方法時, 不在 main() 方法宣告 "throws IOException", 編譯程式時就會出現錯誤。 但我們現在改用 try 來執行 readLine(), 並自行捕捉 IOException 類別的例外, 因此不宣告 "throws IOException" 也能正常編譯成功。

103 自行拋出例外 當我們遇到無法自己處理的例外, 或是想以例外的方式來通知不正常的狀況時, 就可以用 throw 敘述主動拋出例外。
舉例來說, 在 Java 中, 整數運算的除以 0 會引發 ArithmeticException 例外, 但除以浮點數 0.0 時卻不會引發例外, 只會使執行結果變成 NaN (參見第 17 章)。

104 自行拋出例外 如果您希望這個計算也會產生 ArithmeticException 例外, 則可自行將程式設計成發現除數為 0.0 時, 即拋出 ArithmeticException 例外物件。

105 自行拋出例外

106 自行拋出例外

107 自行拋出例外

108 自行抛出例外 在第 18 行我們用 if 敘述判斷使用者輸入的值是否為 0, 因為 0 將使 26 行的運算式無法算出正常結果, 所以我們在 19 行拋出 ArithmeticException 物件, 並自訂該例外物件的訊息。

109 14-4 自訂例外類別 除了自行用 throw 敘述拋出例外物件, 我們也能自訂新的例外類別, 然後在程式中拋出此類自訂類別的例外物件。
但要特別注意, 自訂的例外類別一定要是 Throwable 的衍生類別 (您可用其下的任一個子類別或孫類別來建立自訂的例外類別), 否則無法用 throw 敘述拋出該類別的物件。

110 自訂例外類別 以下的範例程式是個解決雞兔同籠問題的程式, 使用者只需輸入頭的總數和腳的總數, 程式就會算出雞兔各有幾隻。
程式中自訂了一個例外類別 ValueException, 當使用者輸入的數值不能在『雞有兩腳、兔有四腳』的前題下計算出雞免的數量, 程式就會拋出此自訂例外類別的物件。

111 自訂例外類別

112 自訂例外類別

113 自訂例外類別

114 自訂例外類別

115 自訂例外類別

116 自訂例外類別 第 4〜9 行是用 RuntimeException 衍生出我們自訂的 ValueException 例外類別。其中定義了一個建構方法, 但也只是直接呼叫父類別的建構方法。 第 19〜30 行用 do/while 迴圈請使用者輸入頭數和腳數, 若輸入負值則會重新請使用者輸入。

117 自訂例外類別 第 34〜47 行的 try 區塊是在計算雞兔同籠二元聯立方程式, 用『(腳數 - 頭數*2)/2』的運算式即可算出兔子的數量, 但若計算結果不能整除, 表示使用者輸入的數值有問題, 便於 37 行拋出自訂例外類別物件;若能整除, 但商為負值, 也表示有問題, 便在第 42 行拋出例外。 第 48〜51 行 catch 自訂例外類別物件, 第 50 行顯示例外物件的訊息。

118 14-5 綜合演練 會抛出例外的計算階乘程式 字串大小寫轉換應用 模擬汽車耗油及行駛狀況

119 會抛出例外的計算階乘程式 在 節曾介紹一個計算階乘的範例, 我們這次做個小小的修改, 讓它改用拋出例外的方式, 來處理數值超出範圍、以及使用者不想再計算這兩種狀況。

120 會抛出例外的計算階乘程式

121 會抛出例外的計算階乘程式

122 會抛出例外的計算階乘程式

123 會抛出例外的計算階乘程式 第 12〜33 行為計算階乘的 try/catch 區塊, 計算階乘的迴圈在 26、27 行。

124 會抛出例外的計算階乘程式 第 19 行用 if 敘述判斷使用者輸入的值是否大於 20, 若是則拋出 ArithmeticException 例外物件。 第 21 行則判斷使用者輸入的值是否為 0, 若是則拋出 RuntimeException 例外物件。

125 字串大小寫轉換應用 Java 的 String 類別雖有 toUpperCase( )、toLowerCase( ) 可將字串中的字母全部轉成大寫或全轉成小寫, 但如果我們想做的是將字串中小寫的字轉大寫、大寫的字轉小寫, 就要自行設計相關的程式。

126 字串大小寫轉換應用 以下就是一個將字串大小寫互換的範例程式, 這個程式只能轉換純英文字串, 換言之字串中只要含英文字母及空白以外的字元, 程式就不會進行轉換。 範例程式的作法是在此情況下拋出 RuntimeException 例外物件, 並用 catch 區塊捕捉該例外、顯示相關訊息。

127 字串大小寫轉換應用

128 字串大小寫轉換應用

129 字串大小寫轉換應用

130 字串大小寫轉換應用

131 字串大小寫轉換應用 第 14〜39 行的 do/while 迴圈會重複請使用者輸入新字串並進行字串中大小寫變換的動作。
第 18〜37 用 try/catch/finally 敘述進行字串轉換的動作。 第 19〜26 行的 for 迴圈逐一進行字串中每個字元的轉換工作。

132 字串大小寫轉換應用 第 20、21 行先檢查字元是否為英文字母或空白, 是才進行轉換, 不是就在第 27 行拋出 RuntimeException 例外物件。 第 33〜37 行的 finally 區塊會在不論是否發生例外的情況下, 請使用者輸入另一個新字串。 第 38 行檢查使用者輸入的字串是否為 "bye" (不論大小寫), 若是就停止迴圈。

133 模擬汽車耗油及行駛狀況 此範例是用自訂類別來模擬汽車行駛時, 消耗油量的情況。
此自訂類別會記錄汽車油箱的油量及耗油效率 (每公升可行駛的里程數)。並有一個行駛指定里程數的方法, 此方法會在油料不足以行駛完指定的里程時, 拋出自訂的 NoGasException 例外物件。 至於自訂的 NoGasException 例外類別, 則只單純繼承 Exception 類別, 並未改寫或新增任何成員。

134 模擬汽車耗油及行駛狀況

135 模擬汽車耗油及行駛狀況

136 模擬汽車耗油及行駛狀況

137 模擬汽車耗油及行駛狀況

138 模擬汽車耗油及行駛狀況

139 模擬汽車耗油及行駛狀況

140 模擬汽車耗油及行駛狀況 第 4、5 行用 Exception 衍生出自訂的 NoGasException 例外類別。
第 8〜28 行定義一個 MyCar 類別以模擬汽車行走時的耗油情況。此類別有兩個資料成員 GasTank 和 Efficient, 分別記錄目前油量及行走時的耗油效率。

141 模擬汽車耗油及行駛狀況 第 18〜23 行的 go( ) 方法模擬汽車行走的情況, 程式先計算出行走指定距離時所需的油量, 再用 GasTank 減去此次的耗油量, 若剩餘油量小於零, 表示油量不足以走完指定的距離, 便在第 22 行拋出自訂的 NoGasException 例外。

142 模擬汽車耗油及行駛狀況 第 50〜63 行使用 do/while 迴圈請使用者持續輸入要行走的距離, 直到油量用完為止。
第 56〜63 行為呼叫 go( ) 方法時的 try/catch 區塊, 若引發油料不足的例外, 就會由 61 行的 catch 敘述捕捉並輸出油料不足的訊息。


Download ppt "第 14 章 例外處理."

Similar presentations


Ads by Google