Java 编程语言使用_异常_来处理错误和其他异常事件。
异常是程序执行期间发生的事件,它会打断指令的正常执行流程。 在 Java 中,异常是显式抛出的,抛出异常的动作叫作_抛出异常_。 处理异常的动作叫作_捕获异常_。
在 Java 中,所有异常都是 Exception类的子类,而 Exception类本身又是 Throwable类的子类。
Java 区分两种类型的异常:
_受检异常_是应用程序应当预料到并从中恢复的异常情况。
受检异常的一个例子是 FileNotFoundException,当方法试图读取一个不存在的文件时,就会出现这种异常。
这类异常会在编译时检查:抛出受检异常的方法应当在其方法签名中注明这一点,而调用可能抛出受检异常的方法的代码必须处理它,否则代码将无法编译。
所有受检异常都是 Exception的子类,且不继承 RuntimeException。
_非受检异常_是应用程序通常无法预料、也无法从中恢复的异常情况。
非受检异常的一个例子是 NullPointerException,当方法期望得到非空值、却收到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
}
}
从方法中抛出非受检异常时,不要求在方法签名中注明这一点,不过这样做也是支持的。
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和+时,返回符合以下格式的 String: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"
本任务中需要实现的主要方法是 CalculatorConundrum.calculate() 方法。
它接收三个实参。
前两个实参operand1和operand2是要进行运算的整数。
第三个实参operation的类型是 String,本练习需要实现以下运算:
+ String 进行加法* String 进行乘法/ String 进行除法更新 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"