轨道
/
Java
Java
/
练习
/
计算器难题
计算器难题

计算器难题

学习练习

简介

异常

Java 编程语言使用_异常_来处理错误和其他异常事件。

什么是异常

异常是程序执行期间发生的事件,它会打断指令的正常执行流程。 在 Java 中,异常是显式抛出的,抛出异常的动作叫作_抛出异常_。 处理异常的动作叫作_捕获异常_。

在 Java 中,所有异常都是 Exception类的子类,而 Exception类本身又是 Throwable类的子类。

Java 区分两种类型的异常:

  1. 受检异常
  2. 非受检异常
受检异常

_受检异常_是应用程序应当预料到并从中恢复的异常情况。 受检异常的一个例子是 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"

1. 实现 calculate 方法,支持几种基本运算

本任务中需要实现的主要方法是 CalculatorConundrum.calculate() 方法。 它接收三个实参。 前两个实参operand1和operand2是要进行运算的整数。 第三个实参operation的类型是 String,本练习需要实现以下运算:

  • 使用 + String 进行加法
  • 使用 * String 进行乘法
  • 使用 / String 进行除法

2. 处理非法运算

更新 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"

3. 处理除以零时抛出的异常

在 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"
通过 GitHub 编辑 链接将在新窗口或新标签页中打开
Java Exercism

准备好开始 计算器难题 了吗?

注册 Exercism,借助 26 个概念158 个练习 和真人导师指导,学习并掌握 Java,全部免费。