Java 程式語言使用_例外_來處理錯誤和其他異常事件。
例外是在程式執行期間發生、會打斷指令正常流程的事件。 在 Java 中,例外是明確地被拋出的,而拋出例外的動作稱為_拋出例外_。 處理例外的動作則稱為_捕捉例外_。
在 Java 中,所有例外都是Exception類別的子類別,而Exception本身又是Throwable的子類別。
Java 將例外區分為 2 種:
_受檢例外_是應用程式應該預期,並能從中復原的異常狀況。
受檢例外的一個例子是FileNotFoundException,當方法試圖讀取不存在的檔案時就會發生。
這類例外會在編譯期受到檢查:拋出受檢例外的方法必須在方法簽章中註明,而呼叫可能拋出受檢例外的方法的程式碼則必須處理它,否則程式碼無法編譯。
所有受檢例外都是Exception的子類別,且不繼承RuntimeException。
_未受檢例外_是應用程式通常無法預期、也無法從中復原的異常狀況。
未受檢例外的一個例子是NullPointerException,當方法預期收到非 null 的值,卻收到null時就會發生。
這類例外不會在編譯期受到檢查:拋出未受檢例外的方法不必在方法簽章中註明,而呼叫可能拋出未受檢例外的方法的程式碼也不一定要處理它。
所有未受檢例外都繼承自RuntimeException,而RuntimeException本身則是Exception的延伸。
Java 中的方法可以使用throw敘述來拋出例外。
從方法拋出受檢例外時,必須使用throws關鍵字在方法簽章中註明,如下方範例所示。
這會強制呼叫端的程式碼預期例外可能被拋出,並據此處理。
public class InsufficientBalanceException extends Exception {
}
public class BankAccount {
public void withdraw(double amount) throws InsufficientBalanceException {
if (balance < amount) {
throw new InsufficientBalanceException();
}
// rest of the method implementation
}
}
從方法拋出未受檢例外時,不一定要在方法簽章中註明,雖然 Java 也支援這樣做。
public class BankAccount {
public void withdraw(double amount) {
if (amount < 0) {
throw new IllegalArgumentException("Cannot withdraw a negative amount");
}
// rest of the method implementation
}
}
在 Java 中,處理例外是透過try、catch和finally關鍵字來完成。
try區塊中。try區塊後面接著一個或多個catch區塊,用來捕捉try區塊中拋出的例外。catch區塊後面可以選擇性地加上finally區塊,它會在try區塊之後一律執行,無論是否拋出例外。以下範例示範這些關鍵字如何運作:
public class ATM {
public void withdraw(BankAccount bankAccount, double amount) {
try {
System.out.println("Withdrawing " + amount);
bankAccount.withdraw(amount);
System.out.println("Withdrawal succeeded");
} catch (InsufficientBalanceException) {
System.out.println("Withdrawal failed: insufficient balance");
} catch (RuntimeException e) {
System.out.println("Withdrawal failed: " + e.getMessage());
} finally {
System.out.println("Current balance: " + bankAccount.getBalance());
}
}
}
在這個範例中,沒有拋出例外時會印出以下內容:
Withdrawing 10.0
Withdrawal succeeded
Current balance: 5.0
不過,如果bankAccount.withdraw(amount)敘述拋出InsufficientBalanceException,就會印出以下內容:
Withdrawing 10.0
Withdrawal failed: insufficient balance
Current balance: 5.0
或者,如果bankAccount.withdraw(amount)拋出未受檢例外,就會印出以下內容:
Withdrawing -10.0
Withdrawal failed: Cannot withdraw a negative amount
Current balance: 5.0
Java 另外還有一個稱為_錯誤_的獨立類別,指的是應用程式外部的嚴重問題。
錯誤的一個例子是OutOfMemoryError,當應用程式試圖使用超過系統可用記憶體時就會發生。
和未受檢例外一樣,錯誤不會在編譯期受到檢查。 差別在於,它們代表系統層級的問題,通常是由 Java 虛擬機器或環境拋出,而不是應用程式。 應用程式通常不應該嘗試捕捉或處理它們。
Java 中的所有錯誤都繼承自Error類別。
在這個練習中,你將為一個簡單的整數計算機建立錯誤處理。 為了讓事情單純一些,我們已經提供了計算加法、乘法和除法的方法。
目標是做出一個能正常運作的計算機,當傳入引數 16、51 和 + 時,它會回傳符合以下模式的字串:16 + 51 = 67。
CalculatorConundrum calculator = new CalculatorConundrum();
calculator.calculate(16, 51, "+");
// => returns "16 + 51 = 67"
calculator.calculate(32, 6, "*");
// => returns "32 * 6 = 192"
calculator.calculate(512, 4, "/");
// => returns "512 / 4 = 128"
calculate 方法以支援幾種基本運算這個任務中主要要實作的方法是 CalculatorConundrum.calculate() 方法。
它接受三個引數。
前兩個引數 operand1 和 operand2 是要進行運算的整數。
第三個引數 operation 的型別是字串,而在這個練習中,必須實作以下運算:
+ 字串的加法* 字串的乘法/ 字串的除法更新 CalculatorConundrum.calculate() 方法,以處理不合法的運算:
operation 引數是 null 時,應該拋出 IllegalArgumentException,訊息為 Operation cannot be null。operation 引數是 "" 時,應該拋出 IllegalArgumentException,訊息為 Operation cannot be empty。operation 引數是 +、* 或 / 以外的任何運算時,應該拋出 IllegalOperationException,訊息為 Operation '{operation}' does not exist。calculator.calculate(10, 1, null);
// => throws IllegalArgumentException with message "Operation cannot be null"
calculator.calculate(10, 1, "");
// => throws IllegalArgumentException with message "Operation cannot be empty"
calculator.calculate(10, 1, "-");
// => throws IllegalOperationException with message "Operation '-' does not exist"
在 Java 中,嘗試除以零會拋出 ArithmeticException。
更新 CalculatorConundrum.calculate() 方法來攔截這個例外,然後拋出 IllegalOperationException,訊息為 Division by zero is not allowed,並以攔截到的 ArithmeticException 作為它的原因。
calculator.calculate(512, 0, "/");
// => throws IllegalOperationException with message "Division by zero is not allowed"