CodeGym /コース /JAVA 25 SELF /例外の伝播(throws)

例外の伝播(throws)

JAVA 25 SELF
レベル 11 , レッスン 4
使用可能

1. はじめに

プログラミングでは、メソッドがエラーに遭遇しても、適切な対処方法がわからないことがよくあります。たとえばメソッドがファイルを読み込むとして、ファイルが存在しない場合にどうするか(ユーザーに確認する? プログラムを終了する? 別のファイルを試す?)はメソッド自身には決められません。こうした場合、メソッドは自分で処理せず、呼び出し元に「責任を渡す」—すなわち例外を呼び出しチェーンの上流へ「伝播」させることができます。

例外の伝播 は、メソッドが自分でエラーを処理せず、呼び出し側に「問題が起きたので、そちらで対処してください」と伝えるための仕組みです。

たとえ: あなたがコールセンターの担当者だとします。お客さんから自分では答えられない質問が来ました。あてずっぽうで答えるのではなく、「専門担当におつなぎします」と伝えます。質問を「上流へ回す(伝播させる)」わけです。

キーワード throws:どのように動作するか

Java では、メソッド宣言でキーワード throws を使って例外の伝播を示します。

構文:

tip_vozvrashchaemogo_znacheniya imyaMetoda(...) throws ExceptionType 
{
    // メソッド本体
}

throws の後には、そのメソッド内で発生し得る例外型を列挙します。これは他の開発者への注意喚起です。「注意! このメソッドはこの型の例外をスローする可能性があります。備えてください」

例:

public void readFile(String filename) throws FileNotFoundException 
{
    FileReader reader = new FileReader(filename); // FileNotFoundException をスローする可能性がある
    // ...
}

ここでは readFile メソッドは自分でエラーを処理せず、「FileNotFoundException をスローするかもしれないので、呼び出し元で対処してほしい」と宣言しています。

2. 呼び出し側はどう対応すべきか?

throws を宣言しているメソッドを呼び出す場合、対応は2つあります:

  • try-catch で処理する
  • 自分のメソッドでも throws を付けてさらに伝播させる

方法 1: try-catch で処理する

public static void main(String[] args) 
{
    try 
    {
        readFile("data.txt");
    } 
    catch (FileNotFoundException e) 
    {
        System.out.println("ファイルが見つかりません: " + e.getMessage());
    }
}

ここでは例外を捕捉し、何をするか(たとえばユーザーにメッセージを表示する)を自分で決めています。

方法 2: さらに伝播させる

public static void main(String[] args) throws FileNotFoundException 
{
    readFile("data.txt");
}

この場合、エラー処理の責任は main を呼び出す側(通常は JVM)に移ります。処理されないままだと、プログラムはエラーメッセージを出して終了します。

3. 例: throws を用いたファイル読み取り

IOExceptionmain レベルでの処理を含む完全な例:

import java.io.*;

public class FileDemo 
{
    // このメソッドは IOException をスローする可能性があることを宣言する
    public static void printFirstLine(String filename) throws IOException 
    {
        BufferedReader reader = new BufferedReader(new FileReader(filename));
        String line = reader.readLine();
        System.out.println("最初の行: " + line);
        reader.close();
    }

    public static void main(String[] args) 
    {
        try 
        {
            printFirstLine("nofile.txt");
        } 
        catch (IOException e) 
        {
            System.out.println("ファイル読み取り時のエラー: " + e.getMessage());
        }
    }
}

メソッド printFirstLine は、ファイルがないときにどうすべきかを知りません—例外をそのまま伝播します。main 側で例外を捕捉してメッセージを表示します。

4. 有用なポイント

いつ、なぜ例外の伝播を使うのか?

  • メソッドがエラー処理を決められない/決めるべきでない場合(ライブラリコードなど)。
  • エラー処理がコンテキストに依存する場合(あるケースでは終了、別のケースでは別ファイルを試すなど)。
  • 不要な try-catch でコードを汚さないため。

ベストプラクティス: 意味のある処理ができないなら例外は伝播させましょう。形だけの捕捉は避けてください。

複数の例外をスロー宣言できる

public void process() throws IOException, SQLException 
{
    // ...
}

チェック例外と非チェック例外の復習

チェック例外(例: IOExceptionSQLException)は、コンパイラが処理または伝播(throws)の宣言を要求します。

非チェック例外(例: NullPointerExceptionIllegalArgumentException)は、コンパイラが処理を要求しないため、throws に明記する必要はありません。

5. 例外を伝播させる際の典型的なミス

エラー № 1: チェック例外に対する throws の宣言を忘れる。
メソッドがチェック例外をスローし得るのに、throws に記載せず、かつ try-catch でも処理していない場合、コンパイラはエラーを報告します。

エラー № 2: 例外を捕捉するが、何もしない。
catch (Exception e) {} は悪いプラクティスです! 対処法がないなら、むしろ例外を上位へ伝播させましょう。

エラー № 3: あまりに広い型でスロー宣言する。
メソッドが FileNotFoundException しか起こし得ないのに、throws Exception と書くのは、コード理解を難しくします。

エラー № 4: 非チェック例外を throws に列挙する。
throwsNullPointerException などをわざわざ書く意味はありません—コンパイラはそれを要求せず、エラー処理の助けにもなりません。

コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION