Menu
CoddyTech

Ngoại lệ tùy chỉnh

Thuộc phần Lập trình hướng đối tượng trong hành trình Java của Coddy. Bài học 60 trên 87.

Các ngoại lệ có sẵn của Java xử lý nhiều tình huống lỗi phổ biến, nhưng đôi khi bạn cần những ngoại lệ riêng cho lĩnh vực của ứng dụng. Ngoại lệ tùy chỉnh giúp bạn tạo các kiểu lỗi có ý nghĩa, diễn đạt rõ vấn đề đã xảy ra.

Để tạo ngoại lệ tùy chỉnh, bạn chỉ cần kế thừa từ một lớp ngoại lệ hiện có. Với ngoại lệ đã kiểm tra (checked exception), hãy kế thừa từ Exception:

public class InsufficientFundsException extends Exception {
    public InsufficientFundsException(String message) {
        super(message);
    }
}

Với ngoại lệ không cần kiểm tra, hãy kế thừa RuntimeException:

public class InvalidAgeException extends RuntimeException {
    public InvalidAgeException(String message) {
        super(message);
    }
}

Lời gọi super(message) truyền thông báo lỗi cho lớp cha, giúp bạn có thể truy cập thông báo đó qua getMessage(). Sau đó, bạn có thể ném và bắt ngoại lệ tùy chỉnh như mọi ngoại lệ khác:

public void withdraw(double amount) throws InsufficientFundsException {
    if (amount > balance) {
        throw new InsufficientFundsException("Balance too low: " + balance);
    }
    balance -= amount;
}

// Sử dụng phương thức này
try {
    account.withdraw(1000);
} catch (InsufficientFundsException e) {
    System.out.println(e.getMessage());
}

Ngoại lệ tùy chỉnh giúp code dễ đọc hơn và cho phép bên gọi xử lý riêng từng tình huống lỗi cụ thể. Chúng đặc biệt hữu ích khi xây dựng API hoặc thư viện, nơi việc truyền đạt lỗi rõ ràng rất quan trọng.

challenge icon

Thử thách

Dễ

Hãy xây dựng một hệ thống đặt vé sử dụng ngoại lệ tùy chỉnh để xử lý các tình huống lỗi khác nhau! Bạn sẽ tạo các kiểu ngoại lệ có ý nghĩa, giúp nêu rõ vấn đề xảy ra khi đặt vé.

Bạn sẽ sắp xếp code trong bốn tệp:

  • TicketSoldOutException.java: Tạo một ngoại lệ có kiểm tra tùy chỉnh (kế thừa Exception) cho trường hợp không còn vé. Ngoại lệ của bạn cần nhận một thông báo trong hàm khởi tạo và truyền thông báo đó cho lớp cha bằng super(message).
  • InvalidSeatException.java: Tạo một ngoại lệ không kiểm tra tùy chỉnh (kế thừa RuntimeException) cho trường hợp có người cố đặt một số ghế không hợp lệ. Ngoại lệ này cũng cần nhận và truyền thông báo cho lớp cha.
  • TicketBooth.java: Tạo một lớp quản lý việc bán vé. Quầy vé cần theo dõi tổng số ghế còn trống và số ghế hợp lệ lớn nhất. Bao gồm:

    Một hàm khởi tạo nhận tổng số ghế còn trống.

    Một phương thức bookTicket(int seatNumber) để xác thực việc đặt vé. Nếu không còn vé (số ghế còn trống bằng 0 hoặc nhỏ hơn), hãy ném một TicketSoldOutException với thông báo "No tickets remaining". Nếu số ghế nhỏ hơn 1 hoặc lớn hơn tổng số ghế, hãy ném một InvalidSeatException với thông báo "Seat [seatNumber] does not exist". Nếu không, hãy giảm số ghế còn trống đi 1 và in ra Booked seat [seatNumber] successfully.

    Một phương thức getAvailableSeats() trả về số ghế còn trống hiện tại.

  • Main.java: Kết hợp các thành phần của hệ thống đặt vé! Bạn sẽ nhận hai đầu vào: tổng số ghế và số ghế cần đặt.

    Tạo một TicketBooth với tổng số ghế đã cho. Sau đó, thử đặt số ghế đã chỉ định bên trong khối try-catch. Vì TicketSoldOutException là ngoại lệ có kiểm tra, bạn phải xử lý nó. Bắt TicketSoldOutException trước và in ra Booking failed: [exception message]. Sau đó, bắt InvalidSeatException và in ra cùng định dạng: Booking failed: [exception message].

    Sau khối try-catch, hãy in ra Remaining seats: [count] bằng phương thức getter.

Bạn sẽ nhận hai đầu vào theo thứ tự: tổng số ghế (số nguyên) và số ghế cần đặt (số nguyên).

Hãy chú ý cách ngoại lệ có kiểm tra buộc bên gọi phải xử lý chúng (bằng try-catch hoặc throws), còn ngoại lệ không kiểm tra thì không yêu cầu xử lý tường minh. Hãy chọn kiểu ngoại lệ dựa trên việc bên gọi có nên dự đoán và khắc phục lỗi đó hay không!

Tự làm thử

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: Tạo TicketBooth với tổng số ghế đã cho
        
        // TODO: Dùng khối try-catch để thử đặt ghế
        // Trước tiên, bắt ngoại lệ (exception) TicketSoldOutException và in ra "Booking failed: [exception message]"
        // Bắt InvalidSeatException và in ra "Booking failed: [exception message]"
        
        // TODO: Sau khối try-catch, in ra "Remaining seats: [count]"
    }
}
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Lập trình hướng đối tượng

Tự luyện tập: Trình biên dịch Java online