カスタム例外
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: チケットシステムをまとめましょう!2つの入力(総座席数と予約する座席番号)を受け取ります。指定された総座席数で
TicketBoothを作成します。次に、try-catchブロック内で指定された座席番号の予約を試みます。TicketSoldOutExceptionはチェック例外であるため、処理する必要があります。まずTicketSoldOutExceptionをキャッチし、"Booking failed: " + e.getMessage()と出力します。次にInvalidSeatExceptionをキャッチし、同じ形式"Booking failed: " + e.getMessage()で出力します。try-catchブロックの後、ゲッターメソッドを使用して
"Remaining seats: " + booth.getAvailableSeats()と出力します。
入力は、総座席数(整数)と予約する座席番号(整数)の順に2つ受け取ります。
チェック例外は呼び出し側に(try-catchまたはthrowsによる)処理を強制するのに対し、非チェック例外は明示的な処理を必要としないことに注目してください。エラーが呼び出し側で予測し、回復すべきものであるかどうかに基づいて例外タイプを選択しましょう!
チートシート
カスタム例外を作成するには、既存の例外クラスを継承します。
チェック例外(Checked Exception)の場合は、Exceptionを継承します:
public class InsufficientFundsException extends Exception {
public InsufficientFundsException(String message) {
super(message);
}
}非チェック例外(Unchecked Exception)の場合は、RuntimeExceptionを継承します:
public class InvalidAgeException extends RuntimeException {
public InvalidAgeException(String message) {
super(message);
}
}super(message)の呼び出しは、エラーメッセージを親クラスに渡し、getMessage()を通じて利用できるようにします。
カスタム例外は、他の例外と同じようにスロー(throw)およびキャッチ(catch)します:
public void withdraw(double amount) throws InsufficientFundsException {
if (amount > balance) {
throw new InsufficientFundsException("Balance too low: " + balance);
}
balance -= amount;
}
// Using it
try {
account.withdraw(1000);
} catch (InsufficientFundsException e) {
System.out.println(e.getMessage());
}チェック例外は、呼び出し側に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]" と出力します
}
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
4継承
継承の基本 (extends)super キーワードメソッドのオーバーライド (@Override)コンストラクタチェーンObject クラス単一継承と多段階継承なぜ多重継承ができないのかまとめ:従業員の階層構造