[Java] 例外を発生させるthrowsとは?throwとの違いも解説

throwsは、メソッドが例外をスローする可能性があることを宣言するために使用されます。

これにより、メソッドを呼び出す側に例外処理を強制します。

一方、throwは実際に例外を発生させるために使います。

例えば、throw new Exception("エラーメッセージ")のように、特定の条件で例外を明示的にスローします。

throwsは宣言、throwは実行という違いがあります。

この記事でわかること
  • throwsとthrowの役割の違い
  • 複数の例外をthrowsで宣言する方法
  • カスタム例外を作成して使用する方法
  • 条件に応じた例外のスロー方法
  • 例外の再スローとラッピングの技術

目次から探す

throwsとは?

Javaにおけるthrowsは、メソッドが特定の例外をスローする可能性があることを宣言するためのキーワードです。

これにより、メソッドを呼び出す側は、例外処理を行うことが求められます。

throwsを使用することで、プログラムの可読性や保守性が向上します。

throwsの基本的な使い方

throwsはメソッドのシグネチャに追加され、メソッドがスローする可能性のある例外を指定します。

以下はその基本的な使い方の例です。

import java.io.IOException;
public class App {
    public static void main(String[] args) {
        try {
            methodThatThrowsException();
        } catch (IOException e) {
            System.out.println("IOExceptionが発生しました: " + e.getMessage());
        }
    }
    // IOExceptionをスローするメソッド
    public static void methodThatThrowsException() throws IOException {
        throw new IOException("エラーが発生しました。");
    }
}
IOExceptionが発生しました: エラーが発生しました。

throwsで宣言できる例外の種類

throwsで宣言できる例外は、主に以下の2種類に分類されます。

スクロールできます
例外の種類説明
チェック例外コンパイル時にチェックされる例外。
アンチェック例外実行時に発生する例外で、チェックされない。

チェック例外は、IOExceptionSQLExceptionなどがあり、メソッドで必ず処理する必要があります。

一方、アンチェック例外は、NullPointerExceptionArrayIndexOutOfBoundsExceptionなどがあり、必ずしも処理する必要はありません。

throwsを使う理由

throwsを使用する理由は以下の通りです。

  • 明示的な例外処理: メソッドがスローする可能性のある例外を明示的に示すことで、呼び出し元に例外処理を促します。
  • コードの可読性向上: 例外の発生を予測しやすくなり、コードの理解が容易になります。
  • 保守性の向上: 例外処理を適切に行うことで、プログラムの安定性が向上します。

throwsを使う際の注意点

throwsを使用する際には、以下の点に注意が必要です。

  • 例外の種類を正確に指定: スローする可能性のある例外を正確に指定しなければなりません。
  • 例外処理の実装: 呼び出し元で適切な例外処理を実装する必要があります。
  • メソッドの可読性: 多くの例外をthrowsで宣言すると、メソッドの可読性が低下する可能性があります。

必要な例外のみを宣言することが重要です。

throwsとthrowの違い

Javaにおけるthrowsthrowは、例外処理に関連するキーワードですが、それぞれ異なる役割を持っています。

ここでは、その違いについて詳しく解説します。

宣言と実行の違い

throwsはメソッドがスローする可能性のある例外を宣言するために使用されます。

一方、throwは実際に例外をスローするために使用されます。

以下の表でその違いをまとめます。

スクロールできます
キーワード説明使用場所
throwsメソッドがスローする例外を宣言するメソッドのシグネチャ
throw実際に例外をスローするメソッドの本体内

throwsとthrowの使い分け

throwsthrowは、以下のように使い分けます。

  • throws: メソッドがスローする可能性のある例外を宣言する際に使用します。

これにより、呼び出し元はその例外を処理する必要があります。

  • throw: 実際に例外を発生させる際に使用します。

特定の条件が満たされた場合に、例外をスローするために用います。

以下は、throwsthrowの使い分けの例です。

import java.io.IOException;
public class App {
    public static void main(String[] args) {
        try {
            methodThatThrowsException();
        } catch (IOException e) {
            System.out.println("IOExceptionが発生しました: " + e.getMessage());
        }
    }
    // throwsでIOExceptionを宣言
    public static void methodThatThrowsException() throws IOException {
        // 条件に応じて例外をthrow
        if (true) { // 例として常にtrueを返す
            throw new IOException("エラーが発生しました。");
        }
    }
}

throwsとthrowの組み合わせ方

throwsthrowは、同じメソッド内で組み合わせて使用することができます。

メソッドがスローする可能性のある例外をthrowsで宣言し、特定の条件に基づいてthrowで例外を発生させることができます。

以下はその例です。

import java.io.IOException;
public class App {
    public static void main(String[] args) {
        try {
            methodThatMayThrowException(false); // falseを渡す
            methodThatMayThrowException(true);  // trueを渡す
        } catch (IOException e) {
            System.out.println("IOExceptionが発生しました: " + e.getMessage());
        }
    }
    // throwsでIOExceptionを宣言
    public static void methodThatMayThrowException(boolean shouldThrow) throws IOException {
        if (shouldThrow) {
            // 条件に応じて例外をthrow
            throw new IOException("エラーが発生しました。");
        }
        System.out.println("正常に処理されました。");
    }
}
正常に処理されました。
IOExceptionが発生しました: エラーが発生しました。

このように、throwsthrowを組み合わせることで、柔軟な例外処理が可能になります。

throwsの応用例

throwsを使用することで、さまざまな状況において柔軟な例外処理が可能になります。

ここでは、throwsの応用例をいくつか紹介します。

複数の例外をthrowsで宣言する

メソッドが複数の例外をスローする可能性がある場合、throwsを使ってそれらをカンマで区切って宣言することができます。

以下はその例です。

import java.io.IOException;
import java.sql.SQLException;
public class App {
    public static void main(String[] args) {
        try {
            methodThatThrowsMultipleExceptions();
        } catch (IOException | SQLException e) {
            System.out.println("例外が発生しました: " + e.getMessage());
        }
    }
    // IOExceptionとSQLExceptionをthrowsで宣言
    public static void methodThatThrowsMultipleExceptions() throws IOException, SQLException {
        // 条件に応じて例外をthrow
        if (true) { // 例として常にtrueを返す
            throw new IOException("IOエラーが発生しました。");
        }
        // ここでSQLExceptionをスローすることも可能
        // throw new SQLException("SQLエラーが発生しました。");
    }
}
例外が発生しました: IOエラーが発生しました。

カスタム例外をthrowsで宣言する

独自の例外クラスを作成し、それをthrowsで宣言することも可能です。

以下はカスタム例外を使用した例です。

// カスタム例外クラス
class CustomException extends Exception {
    public CustomException(String message) {
        super(message);
    }
}
public class App {
    public static void main(String[] args) {
        try {
            methodThatThrowsCustomException();
        } catch (CustomException e) {
            System.out.println("カスタム例外が発生しました: " + e.getMessage());
        }
    }
    // カスタム例外をthrowsで宣言
    public static void methodThatThrowsCustomException() throws CustomException {
        throw new CustomException("カスタムエラーが発生しました。");
    }
}
カスタム例外が発生しました: カスタムエラーが発生しました。

メソッドチェーンでのthrowsの活用

メソッドチェーンを使用することで、複数のメソッドを連続して呼び出し、例外を一元的に処理することができます。

以下はその例です。

import java.io.IOException;
public class App {
    public static void main(String[] args) {
        try {
            methodChain();
        } catch (IOException e) {
            System.out.println("IOExceptionが発生しました: " + e.getMessage());
        }
    }
    // メソッドチェーン
    public static void methodChain() throws IOException {
        methodOne();
    }
    public static void methodOne() throws IOException {
        methodTwo();
    }
    public static void methodTwo() throws IOException {
        throw new IOException("メソッドチェーンでエラーが発生しました。");
    }
}
IOExceptionが発生しました: メソッドチェーンでエラーが発生しました。

継承関係におけるthrowsの使い方

継承関係にあるクラスでthrowsを使用する場合、親クラスで宣言した例外を子クラスでオーバーライドする際に、同じ例外またはそのサブクラスを宣言することができます。

以下はその例です。

import java.io.IOException;
class Parent {
    // 親クラスでIOExceptionをthrows
    public void method() throws IOException {
        throw new IOException("親クラスでエラーが発生しました。");
    }
}
class Child extends Parent {
    // 子クラスで親クラスの例外をオーバーライド
    @Override
    public void method() throws IOException {
        super.method(); // 親クラスのメソッドを呼び出す
    }
}
public class App {
    public static void main(String[] args) {
        Child child = new Child();
        try {
            child.method();
        } catch (IOException e) {
            System.out.println("IOExceptionが発生しました: " + e.getMessage());
        }
    }
}
IOExceptionが発生しました: 親クラスでエラーが発生しました。

このように、throwsはさまざまなシナリオで活用でき、柔軟な例外処理を実現します。

throwの応用例

throwを使用することで、特定の条件に基づいて例外を発生させたり、例外を再スローしたりすることができます。

ここでは、throwの応用例をいくつか紹介します。

カスタム例外をthrowでスローする

独自の例外クラスを作成し、throwを使ってその例外をスローすることができます。

以下はカスタム例外を使用した例です。

// カスタム例外クラス
class MyCustomException extends Exception {
    public MyCustomException(String message) {
        super(message);
    }
}
public class App {
    public static void main(String[] args) {
        try {
            methodThatThrowsCustomException();
        } catch (MyCustomException e) {
            System.out.println("カスタム例外が発生しました: " + e.getMessage());
        }
    }
    // カスタム例外をthrowでスロー
    public static void methodThatThrowsCustomException() throws MyCustomException {
        throw new MyCustomException("カスタムエラーが発生しました。");
    }
}
カスタム例外が発生しました: カスタムエラーが発生しました。

条件に応じて異なる例外をthrowする

特定の条件に基づいて異なる例外をスローすることも可能です。

以下はその例です。

import java.io.IOException;
import java.sql.SQLException;
public class App {
    public static void main(String[] args) {
        try {
            methodThatThrowsBasedOnCondition(true);  // trueを渡す
            methodThatThrowsBasedOnCondition(false); // falseを渡す
        } catch (IOException e) {
            System.out.println("IOExceptionが発生しました: " + e.getMessage());
        } catch (SQLException e) {
            System.out.println("SQLExceptionが発生しました: " + e.getMessage());
        }
    }
    // 条件に応じて異なる例外をthrow
    public static void methodThatThrowsBasedOnCondition(boolean condition) throws IOException, SQLException {
        if (condition) {
            throw new IOException("IOエラーが発生しました。");
        } else {
            throw new SQLException("SQLエラーが発生しました。");
        }
    }
}

このコードを実行すると、最初の呼び出しで以下の出力が得られます。

IOExceptionが発生しました: IOエラーが発生しました。

次の呼び出しでは、以下の出力が得られます。

SQLExceptionが発生しました: SQLエラーが発生しました。

throwを使った例外の再スロー

throwを使用して、捕捉した例外を再スローすることができます。

これにより、例外を上位の呼び出し元に伝えることができます。

以下はその例です。

import java.io.IOException;
public class App {
    public static void main(String[] args) {
        try {
            methodThatThrowsAndCatchesException();
        } catch (IOException e) {
            System.out.println("再スローされたIOExceptionが発生しました: " + e.getMessage());
        }
    }
    // 例外を捕捉して再スロー
    public static void methodThatThrowsAndCatchesException() throws IOException {
        try {
            throw new IOException("元のIOエラーが発生しました。");
        } catch (IOException e) {
            // 例外を再スロー
            throw e;
        }
    }
}
再スローされたIOExceptionが発生しました: 元のIOエラーが発生しました。

throwを使った例外のラッピング

throwを使用して、捕捉した例外を新しい例外でラッピングすることもできます。

これにより、元の例外情報を保持しつつ、より具体的なエラーメッセージを提供できます。

以下はその例です。

import java.io.IOException;
public class App {
    public static void main(String[] args) {
        try {
            methodThatThrowsWrappedException();
        } catch (Exception e) {
            System.out.println("ラッピングされた例外が発生しました: " + e.getMessage());
            System.out.println("元の例外: " + e.getCause().getMessage());
        }
    }
    // 例外をラッピングしてthrow
    public static void methodThatThrowsWrappedException() throws Exception {
        try {
            throw new IOException("元のIOエラーが発生しました。");
        } catch (IOException e) {
            // 新しい例外でラッピングしてthrow
            throw new Exception("ラッピングされたエラーが発生しました。", e);
        }
    }
}
ラッピングされた例外が発生しました: ラッピングされたエラーが発生しました。
元の例外: 元のIOエラーが発生しました。

このように、throwを使用することで、柔軟な例外処理が可能になり、プログラムのエラーハンドリングをより効果的に行うことができます。

よくある質問

throwsとthrowを間違えるとどうなる?

throwsthrowを間違えると、プログラムの動作に影響を及ぼす可能性があります。

具体的には、以下のような問題が発生します。

  • 例外の宣言漏れ: throwsを使わずに例外をスローしようとすると、コンパイルエラーが発生します。

メソッドがスローする可能性のある例外を正しく宣言しないと、Javaコンパイラはそのメソッドを呼び出す際に例外処理が必要であることを認識できません。

  • 実行時エラー: throwを使って例外をスローする際に、適切に例外を処理しないと、実行時に未処理の例外が発生し、プログラムが異常終了する可能性があります。

throwsで宣言した例外をcatchしないとどうなる?

throwsで宣言した例外をcatchしない場合、プログラムはコンパイルエラーにはなりませんが、実行時にその例外が発生すると、未処理の例外としてプログラムが異常終了します。

呼び出し元で例外を適切に処理しないと、エラーメッセージが表示され、スタックトレースが出力されることになります。

これにより、プログラムの安定性が損なわれる可能性があります。

throwでスローした例外は必ずcatchする必要がある?

throwでスローした例外は、必ずしもcatchする必要はありません。

スローされた例外がチェック例外の場合、呼び出し元でcatchするか、再度throwsで宣言する必要があります。

一方、アンチェック例外(RuntimeExceptionのサブクラスなど)は、catchしなくてもプログラムは正常にコンパイルされ、実行されます。

ただし、例外を適切に処理しないと、プログラムが異常終了する可能性があるため、例外処理を行うことが推奨されます。

まとめ

この記事では、Javaにおけるthrowsthrowの使い方やその違い、応用例について詳しく解説しました。

これにより、例外処理の基本的な概念から、実際のプログラムでの活用方法までを理解することができました。

今後は、実際のプロジェクトやコードを書く際に、これらの知識を活かして、より堅牢でエラーに強いプログラムを作成してみてください。

  • URLをコピーしました!
目次から探す