[Java] 例外を発生させるthrowの使い方を解説

Javaで例外を発生させるには、throwキーワードを使用します。

throwの後に例外オブジェクトを指定し、その例外を明示的に発生させます。

例えば、throw new IllegalArgumentException("エラーメッセージ")のように記述します。

throwは通常、メソッド内で使用され、例外が発生するとそのメソッドの実行が中断され、呼び出し元に例外が伝播します。

throwを使う際、発生させる例外がチェック例外の場合、メソッド宣言にthrowsを追加する必要があります。

この記事でわかること
  • throwとthrowsの違いについての理解
  • 例外処理におけるthrowの使い方
  • カスタム例外の作成方法と利点
  • 具体的な例を通じた応用方法
  • 例外処理の重要性と実践的な知識

目次から探す

throwの基本的な使い方

throwとは

throwは、Javaにおいて例外を発生させるためのキーワードです。

プログラムの実行中に異常な状態が発生した場合に、throwを使用して例外オブジェクトを生成し、呼び出し元に通知します。

これにより、エラーハンドリングを行うことが可能になります。

throwの構文

throwを使用する際の基本的な構文は以下の通りです。

throw new ExceptionType("エラーメッセージ");

ここで、ExceptionTypeは発生させたい例外のクラス名で、"エラーメッセージ"は例外の詳細情報を示す文字列です。

throwとthrowsの違い

throwthrowsは異なる役割を持つキーワードです。

スクロールできます
キーワード役割
throw例外を発生させる
throwsメソッドが例外をスローする可能性を示す

throwは実際に例外を発生させるために使用され、throwsはメソッドの宣言部分で使用され、呼び出し元に例外が発生する可能性を伝えます。

例外オブジェクトの生成方法

例外オブジェクトは、newキーワードを使用して生成します。

以下は、IllegalArgumentExceptionを生成する例です。

IllegalArgumentException exception = new IllegalArgumentException("不正な引数です。");

このようにして生成した例外オブジェクトは、throwを使ってスローすることができます。

throwを使うタイミング

throwを使用するタイミングは以下のような場合です。

  • メソッドの引数が不正な値である場合
  • 期待される条件が満たされない場合
  • 外部リソースの操作中にエラーが発生した場合

これらの状況でthrowを使うことで、プログラムの異常を適切に処理し、エラーの原因を特定しやすくなります。

具体的な例:throwの使用例

IllegalArgumentExceptionをthrowする

IllegalArgumentExceptionは、メソッドに渡された引数が不正な場合にスローされる例外です。

以下のサンプルコードでは、引数が負の値の場合にこの例外を発生させます。

public class App {
    public static void main(String[] args) {
        try {
            checkPositive(-1); // 負の値を渡す
        } catch (IllegalArgumentException e) {
            System.out.println(e.getMessage()); // 例外メッセージを表示
        }
    }
    public static void checkPositive(int number) {
        if (number < 0) {
            throw new IllegalArgumentException("引数は正の値でなければなりません。");
        }
    }
}
引数は正の値でなければなりません。

このコードでは、checkPositiveメソッドが負の値を受け取った場合にIllegalArgumentExceptionをスローします。

NullPointerExceptionをthrowする

NullPointerExceptionは、null参照に対してメソッドを呼び出そうとした場合に発生します。

以下のサンプルコードでは、nullのオブジェクトにアクセスしようとした際にこの例外をスローします。

public class App {
    public static void main(String[] args) {
        try {
            String str = null;
            printLength(str); // nullを渡す
        } catch (NullPointerException e) {
            System.out.println(e.getMessage()); // 例外メッセージを表示
        }
    }
    public static void printLength(String str) {
        if (str == null) {
            throw new NullPointerException("文字列はnullであってはいけません。");
        }
        System.out.println("文字列の長さ: " + str.length());
    }
}
文字列はnullであってはいけません。

このコードでは、printLengthメソッドがnullの文字列を受け取った場合にNullPointerExceptionをスローします。

カスタム例外をthrowする

カスタム例外を作成することで、特定のエラー状況をより明確に表現できます。

以下のサンプルコードでは、カスタム例外MyCustomExceptionを定義し、条件に応じてスローします。

public class MyCustomException extends Exception {
    public MyCustomException(String message) {
        super(message);
    }
}
public class App {
    public static void main(String[] args) {
        try {
            validateAge(15); // 不正な年齢を渡す
        } catch (MyCustomException e) {
            System.out.println(e.getMessage()); // 例外メッセージを表示
        }
    }
    public static void validateAge(int age) throws MyCustomException {
        if (age < 18) {
            throw new MyCustomException("年齢は18歳以上でなければなりません。");
        }
    }
}
年齢は18歳以上でなければなりません。

このコードでは、validateAgeメソッドが18歳未満の年齢を受け取った場合にカスタム例外MyCustomExceptionをスローします。

例外メッセージのカスタマイズ

例外メッセージは、エラーの原因を明確にするためにカスタマイズできます。

以下のサンプルコードでは、例外メッセージに詳細な情報を含めています。

public class App {
    public static void main(String[] args) {
        try {
            divide(10, 0); // ゼロで割る
        } catch (ArithmeticException e) {
            System.out.println(e.getMessage()); // 例外メッセージを表示
        }
    }
    public static void divide(int a, int b) {
        if (b == 0) {
            throw new ArithmeticException("ゼロで割ることはできません。a: " + a + ", b: " + b);
        }
        System.out.println("結果: " + (a / b));
    }
}
ゼロで割ることはできません。a: 10, b: 0

このコードでは、divideメソッドがゼロで割ろうとした場合に、具体的な情報を含むArithmeticExceptionをスローします。

throwとtry-catchの連携

try-catchブロックの基本

try-catchブロックは、Javaにおける例外処理の基本的な構造です。

tryブロック内で発生した例外をcatchブロックで捕捉し、適切に処理することができます。

以下は、try-catchブロックの基本的な構文です。

try {
    // 例外が発生する可能性のあるコード
} catch (ExceptionType e) {
    // 例外が発生した場合の処理
}

この構造により、プログラムの異常終了を防ぎ、エラーに対する柔軟な対応が可能になります。

throwとtry-catchの組み合わせ

throwを使用して例外を発生させる場合、try-catchブロックと組み合わせることで、発生した例外を捕捉し、適切に処理することができます。

以下のサンプルコードでは、throwを使って例外を発生させ、その例外をcatchで捕捉しています。

public class App {
    public static void main(String[] args) {
        try {
            validateNumber(0); // 不正な値を渡す
        } catch (IllegalArgumentException e) {
            System.out.println(e.getMessage()); // 例外メッセージを表示
        }
    }
    public static void validateNumber(int number) {
        if (number <= 0) {
            throw new IllegalArgumentException("数値は1以上でなければなりません。");
        }
    }
}
数値は1以上でなければなりません。

このコードでは、validateNumberメソッドが不正な値を受け取った場合にIllegalArgumentExceptionをスローし、catchブロックでその例外を処理しています。

throwで発生させた例外をcatchする

throwで発生させた例外は、catchブロックで捕捉することができます。

以下のサンプルコードでは、throwでスローされた例外をcatchで捕捉し、エラーメッセージを表示しています。

public class App {
    public static void main(String[] args) {
        try {
            checkAge(15); // 不正な年齢を渡す
        } catch (MyCustomException e) {
            System.out.println(e.getMessage()); // 例外メッセージを表示
        }
    }
    public static void checkAge(int age) throws MyCustomException {
        if (age < 18) {
            throw new MyCustomException("年齢は18歳以上でなければなりません。");
        }
    }
}
年齢は18歳以上でなければなりません。

このコードでは、checkAgeメソッドが不正な年齢を受け取った場合にカスタム例外MyCustomExceptionをスローし、catchブロックでその例外を処理しています。

finallyブロックとの関係

finallyブロックは、try-catch構造の一部として使用され、例外の発生に関わらず必ず実行されるコードを記述するために用います。

リソースの解放や後処理を行う際に便利です。

以下のサンプルコードでは、finallyブロックを使用して、例外が発生しても必ず実行される処理を示しています。

public class App {
    public static void main(String[] args) {
        try {
            divide(10, 0); // ゼロで割る
        } catch (ArithmeticException e) {
            System.out.println(e.getMessage()); // 例外メッセージを表示
        } finally {
            System.out.println("処理が完了しました。"); // 常に実行される
        }
    }
    public static void divide(int a, int b) {
        if (b == 0) {
            throw new ArithmeticException("ゼロで割ることはできません。");
        }
        System.out.println("結果: " + (a / b));
    }
}
ゼロで割ることはできません。
処理が完了しました。

このコードでは、divideメソッドがゼロで割ろうとした場合にArithmeticExceptionをスローし、catchブロックでその例外を処理した後、finallyブロックが必ず実行されます。

これにより、例外が発生しても後処理が確実に行われることが保証されます。

throwsとの違いと使い分け

throwsの役割

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

メソッドの宣言部分にthrowsを記述することで、呼び出し元に対してそのメソッドが特定の例外をスローする可能性があることを通知します。

以下は、throwsの基本的な構文です。

public void methodName() throws ExceptionType {
    // メソッドの処理
}

このようにすることで、呼び出し元はそのメソッドを使用する際に、例外処理を行う必要があることを理解できます。

throwとthrowsの併用

throwthrowsは異なる役割を持ちますが、併用することができます。

throwは実際に例外を発生させるために使用され、throwsはそのメソッドが例外をスローする可能性を示します。

以下のサンプルコードでは、throwsを使ってメソッドの宣言を行い、throwを使って例外を発生させています。

public class App {
    public static void main(String[] args) {
        try {
            checkValue(-1); // 不正な値を渡す
        } catch (IllegalArgumentException e) {
            System.out.println(e.getMessage()); // 例外メッセージを表示
        }
    }
    public static void checkValue(int value) throws IllegalArgumentException {
        if (value < 0) {
            throw new IllegalArgumentException("値は0以上でなければなりません。");
        }
    }
}
値は0以上でなければなりません。

このコードでは、checkValueメソッドが不正な値を受け取った場合にIllegalArgumentExceptionをスローし、呼び出し元にその可能性をthrowsで示しています。

throwsを使うべきケース

throwsを使用すべきケースは以下の通りです。

  • メソッド内で例外を処理せず、呼び出し元に処理を委ねたい場合
  • 複数のメソッドで同じ例外をスローする可能性がある場合
  • ライブラリやAPIを提供する際に、利用者に例外処理を明示的に要求したい場合

これにより、メソッドの利用者は、どのような例外が発生する可能性があるかを事前に把握し、適切なエラーハンドリングを行うことができます。

throwとthrowsの誤用を避ける

throwthrowsを誤用しないためには、以下のポイントに注意することが重要です。

  • throwは例外を発生させるために使用し、メソッド内で実行されるべきであることを理解する。
  • throwsはメソッドの宣言部分で使用し、メソッドが例外をスローする可能性を示すものであることを理解する。
  • throwを使ってスローした例外は、必ずtry-catchブロックで捕捉するか、throwsを使って呼び出し元に伝える必要がある。

これらのポイントを押さえることで、throwthrowsを正しく使い分け、効果的な例外処理を実現することができます。

カスタム例外の作成とthrowの活用

カスタム例外クラスの作成方法

カスタム例外クラスは、JavaのExceptionクラスまたはそのサブクラスを継承して作成します。

カスタム例外を作成することで、特定のエラー状況を明確に表現できます。

以下は、カスタム例外クラスの基本的な構造です。

public class MyCustomException extends Exception {
    public MyCustomException(String message) {
        super(message); // 親クラスのコンストラクタを呼び出す
    }
}

このように、カスタム例外クラスを定義することで、特定のエラーに対する例外をスローすることが可能になります。

カスタム例外をthrowする

カスタム例外をスローするには、throwキーワードを使用します。

以下のサンプルコードでは、カスタム例外MyCustomExceptionをスローしています。

public class App {
    public static void main(String[] args) {
        try {
            validateInput(-5); // 不正な入力を渡す
        } catch (MyCustomException e) {
            System.out.println(e.getMessage()); // 例外メッセージを表示
        }
    }
    public static void validateInput(int input) throws MyCustomException {
        if (input < 0) {
            throw new MyCustomException("入力は0以上でなければなりません。");
        }
    }
}
入力は0以上でなければなりません。

このコードでは、validateInputメソッドが不正な入力を受け取った場合にカスタム例外MyCustomExceptionをスローします。

カスタム例外のメリット

カスタム例外を使用することには以下のようなメリットがあります。

  • 明確なエラーハンドリング: 特定のエラー状況を明示的に表現できるため、エラーハンドリングが容易になります。
  • コードの可読性向上: カスタム例外を使用することで、コードの意図が明確になり、可読性が向上します。
  • 特定のエラーに対する処理: 特定のエラーに対して専用の処理を行うことができ、柔軟なエラーハンドリングが可能になります。

カスタム例外の実装例

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

この例では、ユーザーの年齢を検証するメソッドを作成し、年齢が不正な場合にカスタム例外をスローします。

public class AgeValidationException extends Exception {
    public AgeValidationException(String message) {
        super(message); // 親クラスのコンストラクタを呼び出す
    }
}
public class App {
    public static void main(String[] args) {
        try {
            checkAge(15); // 不正な年齢を渡す
        } catch (AgeValidationException e) {
            System.out.println(e.getMessage()); // 例外メッセージを表示
        }
    }
    public static void checkAge(int age) throws AgeValidationException {
        if (age < 18) {
            throw new AgeValidationException("年齢は18歳以上でなければなりません。");
        }
        System.out.println("年齢は適正です。");
    }
}
年齢は18歳以上でなければなりません。

このコードでは、checkAgeメソッドが18歳未満の年齢を受け取った場合にカスタム例外AgeValidationExceptionをスローし、呼び出し元でその例外を処理しています。

これにより、特定のエラー状況に対する明確なエラーハンドリングが実現されています。

throwを使った応用例

メソッドの引数チェックでthrowを使う

メソッドの引数が期待される条件を満たさない場合にthrowを使用して例外を発生させることができます。

以下のサンプルコードでは、引数が負の値の場合にIllegalArgumentExceptionをスローしています。

public class App {
    public static void main(String[] args) {
        try {
            calculateSquareRoot(-4); // 負の値を渡す
        } catch (IllegalArgumentException e) {
            System.out.println(e.getMessage()); // 例外メッセージを表示
        }
    }
    public static double calculateSquareRoot(double number) {
        if (number < 0) {
            throw new IllegalArgumentException("引数は0以上でなければなりません。");
        }
        return Math.sqrt(number);
    }
}
引数は0以上でなければなりません。

このコードでは、calculateSquareRootメソッドが負の値を受け取った場合に例外をスローします。

ファイル操作での例外処理

ファイル操作を行う際には、さまざまな例外が発生する可能性があります。

以下のサンプルコードでは、ファイルが存在しない場合にFileNotFoundExceptionをスローしています。

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class App {
    public static void main(String[] args) {
        try {
            readFile("nonexistent.txt"); // 存在しないファイルを指定
        } catch (FileNotFoundException e) {
            System.out.println(e.getMessage()); // 例外メッセージを表示
        }
    }
    public static void readFile(String fileName) throws FileNotFoundException {
        File file = new File(fileName);
        if (!file.exists()) {
            throw new FileNotFoundException("ファイルが見つかりません: " + fileName);
        }
        Scanner scanner = new Scanner(file);
        // ファイルの読み取り処理
        scanner.close();
    }
}
ファイルが見つかりません: nonexistent.txt

このコードでは、指定されたファイルが存在しない場合にFileNotFoundExceptionをスローします。

データベース接続時の例外処理

データベース接続時にも例外が発生する可能性があります。

以下のサンプルコードでは、接続に失敗した場合にカスタム例外DatabaseConnectionExceptionをスローしています。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class DatabaseConnectionException extends Exception {
    public DatabaseConnectionException(String message) {
        super(message);
    }
}
public class App {
    public static void main(String[] args) {
        try {
            connectToDatabase("jdbc:mysql://localhost:3306/mydb", "user", "password");
        } catch (DatabaseConnectionException e) {
            System.out.println(e.getMessage()); // 例外メッセージを表示
        }
    }
    public static void connectToDatabase(String url, String user, String password) throws DatabaseConnectionException {
        try {
            Connection connection = DriverManager.getConnection(url, user, password);
            // データベース操作
        } catch (SQLException e) {
            throw new DatabaseConnectionException("データベース接続に失敗しました: " + e.getMessage());
        }
    }
}
データベース接続に失敗しました: Access denied for user 'user'@'localhost' (using password: YES)

このコードでは、データベース接続に失敗した場合にカスタム例外をスローします。

ユーザー入力のバリデーションでthrowを活用

ユーザーからの入力を検証する際にもthrowを使用して例外を発生させることができます。

以下のサンプルコードでは、ユーザーの年齢が不正な場合にカスタム例外InvalidAgeExceptionをスローしています。

import java.util.Scanner;
public class InvalidAgeException extends Exception {
    public InvalidAgeException(String message) {
        super(message);
    }
}
public class App {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.print("年齢を入力してください: ");
        int age = scanner.nextInt();
        
        try {
            validateAge(age); // 年齢を検証
        } catch (InvalidAgeException e) {
            System.out.println(e.getMessage()); // 例外メッセージを表示
        }
    }
    public static void validateAge(int age) throws InvalidAgeException {
        if (age < 0 || age > 120) {
            throw new InvalidAgeException("年齢は0以上120以下でなければなりません。");
        }
        System.out.println("年齢は適正です。");
    }
}
年齢を入力してください: -5
年齢は0以上120以下でなければなりません。

このコードでは、ユーザーが不正な年齢を入力した場合にカスタム例外をスローします。

複数の例外をthrowするケース

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

以下のサンプルコードでは、引数の値に応じて異なる例外をスローしています。

public class App {
    public static void main(String[] args) {
        try {
            processInput(0); // 不正な値を渡す
        } catch (IllegalArgumentException | ArithmeticException e) {
            System.out.println(e.getMessage()); // 例外メッセージを表示
        }
    }
    public static void processInput(int value) {
        if (value < 0) {
            throw new IllegalArgumentException("値は0以上でなければなりません。");
        } else if (value == 0) {
            throw new ArithmeticException("ゼロでの処理はできません。");
        }
        System.out.println("処理が成功しました。");
    }
}
ゼロでの処理はできません。

このコードでは、引数の値に応じてIllegalArgumentExceptionまたはArithmeticExceptionをスローします。

これにより、異なるエラー状況に対して適切な例外を発生させることができます。

よくある質問

throwとthrowsの違いは何ですか?

throwthrowsは異なる役割を持つキーワードです。

throwは実際に例外を発生させるために使用され、メソッド内で実行されます。

一方、throwsはメソッドの宣言部分で使用され、そのメソッドが特定の例外をスローする可能性があることを呼び出し元に通知します。

具体的には、throwは例外を発生させるためのアクションであり、throwsはそのアクションが発生する可能性を示すものです。

どのタイミングでthrowを使うべきですか?

throwを使用するタイミングは、主に以下のような場合です。

  • メソッドの引数が不正な値である場合(例:負の数やnullなど)
  • 期待される条件が満たされない場合(例:ユーザーの入力が不正な場合)
  • 外部リソースの操作中にエラーが発生した場合(例:ファイルが見つからない、データベース接続に失敗した場合)

これらの状況でthrowを使うことで、プログラムの異常を適切に処理し、エラーの原因を特定しやすくなります。

カスタム例外を作成するメリットは何ですか?

カスタム例外を作成することには以下のようなメリットがあります。

  • 明確なエラーハンドリング: 特定のエラー状況を明示的に表現できるため、エラーハンドリングが容易になります。
  • コードの可読性向上: カスタム例外を使用することで、コードの意図が明確になり、可読性が向上します。
  • 特定のエラーに対する処理: 特定のエラーに対して専用の処理を行うことができ、柔軟なエラーハンドリングが可能になります。
  • メンテナンス性の向上: カスタム例外を使用することで、エラー処理のロジックを一元化でき、メンテナンスが容易になります。

まとめ

この記事では、Javaにおけるthrowthrowsの使い方、カスタム例外の作成方法、そしてそれらを活用した具体的な応用例について詳しく解説しました。

これにより、例外処理の重要性や、適切なエラーハンドリングの手法についての理解が深まったことでしょう。

今後は、実際のプログラムにおいてこれらの知識を活用し、より堅牢でエラーに強いアプリケーションを開発してみてください。

当サイトはリンクフリーです。出典元を明記していただければ、ご自由に引用していただいて構いません。

関連カテゴリーから探す

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