今回やること
throwsは、メソッド内で起こり得るchecked例外を、自分で処理せず呼び出し元へ伝える宣言です。ファイルを読むメソッドは処理方法を決めず、mainが利用者への表示を決めます。
前提: Java入門 #19 - 例外処理の基本で
try-catch-finallyの流れを学んでいること。
loadMessage() ── IOExceptionをthrows ──→ main()がcatchして表示
| キーワード | 役割 |
|---|---|
throws IOException | このメソッドから例外が伝播し得ると宣言 |
throw new ... | その場所で例外を実際に投げる |
catch | 伝播してきた例外を捕捉して処理 |
1. checked例外を確認する
Files.readStringは、ファイルがない、読み取り権限がないなどの理由でIOExceptionを投げる可能性があります。IOExceptionはchecked例外なので、コンパイラが処理または宣言を求めます。
String text = Files.readString(Path.of(path));
この行を持つメソッドは、内部でtry-catchするか、メソッド宣言へthrows IOExceptionを書く必要があります。
2. 下位メソッドから伝播する
static String loadMessage(String path) throws IOException {
return Files.readString(Path.of(path));
}
loadMessageは「ファイルを読み、文字列を返す」ことに集中します。ファイルがない時に再入力させるか、終了するか、別の値を使うかは決めません。
throwsを書いても例外を解決したことにはなりません。呼び出し元が、さらにthrowsするかcatchする責任を引き受けます。
3. 処理の境界でcatchする
今回は利用者へ結果を表示するmainで捕捉します。
try {
String message = loadMessage("message.txt");
System.out.println("読み込み: " + message);
} catch (IOException e) {
System.out.println("message.txtを読み込めませんでした");
}
低い層のメソッドが勝手にプログラムを終了せず、利用者との境界に近い場所が表示方法を決めています。
完成コードを動かす
同じディレクトリにmessage.txtを作り、内容をJavaの例外処理とします。次にThrowsDemo.javaを保存します。
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
public class ThrowsDemo {
static String loadMessage(String path) throws IOException {
return Files.readString(Path.of(path)).trim();
}
public static void main(String[] args) {
try {
String message = loadMessage("message.txt");
System.out.println("読み込み: " + message);
} catch (IOException e) {
System.out.println("message.txtを読み込めませんでした");
}
}
}
javac ThrowsDemo.java
java ThrowsDemo
loadMessageを呼ぶ側がcatchを削除すると、mainもthrows IOExceptionを宣言しない限りコンパイルエラーになります。checked例外が呼び出し経路で無視されない仕組みです。
成功確認
ファイルがある時は次のように表示されます。
読み込み: Javaの例外処理
次にmessage.txtの名前を一時的に変えて実行し、次が表示されることも確認します。
message.txtを読み込めませんでした
成功と失敗の両方が、同じmainの境界で扱われれば完了です。
catchする場所を決める
すべてのメソッドへ機械的にthrows Exceptionを付けると、どの失敗が起きるか分からなくなります。具体的なIOExceptionを宣言し、回復方法を決められる場所でcatchします。
| 場所 | この例での責務 |
|---|---|
loadMessage | ファイルを読み、失敗をIOExceptionとして伝える |
main | 利用者に成功または失敗を表示する |
原因調査用の詳細をログへ残す場合でも、ファイル内容や個人情報を無条件に出さないようにします。
よくあるつまずき
throwsを書けば例外処理が終わると思う
処理を呼び出し元へ移しただけです。どこかの境界でcatchするか、さらに上へ伝える必要があります。
throwとthrowsを混同する
throwは例外オブジェクトを投げる文、throwsはメソッドが伝播し得る例外を宣言する部分です。
広いExceptionだけを使う
何が失敗するか分からなくなります。まずAPIが宣言する具体的な例外型を確認します。
練習
score.txtから文字列を読むloadScore(String path) throws IOExceptionを作り、mainで表示してください。ファイルがない場合は「点数を読み込めません」と表示します。
次のステップ
Java入門 #21 - 継承で、既存クラスの機能を引き継ぐ方法を学びます。