自定义异常
本课属于 Coddy Java 学习旅程的“面向对象编程”单元。第 60 课,共 87 课。
Java 内置的异常涵盖了许多常见的错误场景,但有时你需要创建适用于应用领域的特定异常。自定义异常可以让你创建有明确含义的错误类型,清楚地说明出了什么问题。
要创建自定义异常,只需扩展现有的异常类。对于已检查异常,扩展 Exception:
public class InsufficientFundsException extends Exception {
public InsufficientFundsException(String message) {
super(message);
}
}对于未经检查的异常,继承 RuntimeException:
public class InvalidAgeException extends RuntimeException {
public InvalidAgeException(String message) {
super(message);
}
}super(message) 调用会将错误消息传递给父类,因此可以通过 getMessage() 获取该消息。然后,你可以像处理其他异常一样,抛出并捕获自定义异常:
public void withdraw(double amount) throws InsufficientFundsException {
if (amount > balance) {
throw new InsufficientFundsException("Balance too low: " + balance);
}
balance -= amount;
}
// 使用它
try {
account.withdraw(1000);
} catch (InsufficientFundsException e) {
System.out.println(e.getMessage());
}自定义异常能让代码更易读,也能让调用者针对特定错误情况采取不同的处理方式。在构建 API 或库时,清晰地传达错误尤其重要,因此自定义异常也特别有用。
挑战
简单让我们构建一个使用自定义异常处理不同错误情况的票务预订系统!你将创建有意义的异常类型,清楚地说明预订门票时出了什么问题。
你将把代码分成 4 个文件:
TicketSoldOutException.java:创建一个自定义受检异常(继承Exception),用于表示门票已售罄。异常的构造函数应接收一条消息,并使用super(message)将消息传递给父类。InvalidSeatException.java:创建一个自定义非受检异常(继承RuntimeException),用于表示有人尝试预订无效的座位号。这个异常也应接收一条消息,并将其传递给父类。TicketBooth.java:创建一个管理门票销售的类。售票处应记录可用座位总数和有效座位号的最大值。包括:一个接收可用座位总数的构造函数。
一个用于验证预订的
bookTicket(int seatNumber)方法。如果没有剩余门票(可用座位数小于或等于 0),则抛出消息为"No tickets remaining"的TicketSoldOutException。如果座位号小于 1 或大于座位总数,则抛出消息为"Seat [seatNumber] does not exist"的InvalidSeatException。否则,将可用座位数减 1,并输出Booked seat [seatNumber] successfully。一个返回当前可用座位数的
getAvailableSeats()方法。Main.java:把票务系统组合起来!你会收到两个输入:座位总数和要预订的座位号。使用给定的座位总数创建一个
TicketBooth。然后在 try-catch 代码块中尝试预订指定座位号。由于TicketSoldOutException是受检异常,你必须处理它。先捕获TicketSoldOutException,并输出Booking failed: [exception message]。然后捕获InvalidSeatException,并以相同格式输出:Booking failed: [exception message]。在 try-catch 代码块之后,使用 getter 方法输出
Remaining seats: [count]。
你会按顺序收到两个输入:座位总数(整数)和要预订的座位号(整数)。
注意,受检异常会要求调用方处理它们(使用 try-catch 或 throws),而非受检异常不需要显式处理。请根据错误是否属于调用方应该预料到并进行恢复的情况,选择异常类型!
亲手试试
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int totalSeats = scanner.nextInt();
int seatNumber = scanner.nextInt();
// TODO: 根据给定的座位总数创建 TicketBooth
// TODO: 使用 try-catch 块尝试预订座位
// 先捕获 TicketSoldOutException,并打印 "Booking failed: [exception message]"
// 捕获 InvalidSeatException,并打印 "Booking failed: [exception message]"
// TODO: 在 try-catch 块之后,打印 "Remaining seats: [count]"
}
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Java 在线编译器