1. 概要

このチュートリアルでは、Javaでカスタム例外を作成する方法について説明します。

チェックされた例外とチェックされていない例外の両方に対して、ユーザー定義の例外がどのように実装および使用されるかを示します。

2. カスタム例外の必要性

Javaの例外は、プログラミングで発生する可能性のあるほとんどすべての一般的な例外をカバーしています。

ただし、これらの標準的な例外を独自のもので補足する必要がある場合があります。

カスタム例外を導入する主な理由は次のとおりです。

  • ビジネスロジックの例外–ビジネスロジックとワークフローに固有の例外。 これらは、アプリケーションユーザーまたは開発者が正確な問題が何であるかを理解するのに役立ちます。
  • 既存のJava例外のサブセットをキャッチして特定の処理を提供するため

Javaの例外は、チェックすることもチェックを外すこともできます。 次のセクションでは、これらの両方のケースについて説明します。

3. カスタムチェック例外

チェックされた例外は、明示的に処理する必要がある例外です。

ファイルの最初の行を返すコードを考えてみましょう。

try (Scanner file = new Scanner(new File(fileName))) {
    if (file.hasNextLine()) return file.nextLine();
} catch(FileNotFoundException e) {
    // Logging, etc 
}

上記のコードは、Javaでチェックされた例外を処理する古典的な方法です。 コードはFileNotFoundExceptionをスローしますが、正確な原因が何であるか(ファイルが存在しないか、ファイル名が無効であるか)は明確ではありません。

カスタム例外を作成するには、java.lang.Exceptionクラスを拡張する必要があります。

IncorrectFileNameException というカスタムチェック例外を作成して、この例を見てみましょう。

public class IncorrectFileNameException extends Exception { 
    public IncorrectFileNameException(String errorMessage) {
        super(errorMessage);
    }
}

エラーメッセージとしてStringを受け取り、親クラスコンストラクターと呼ばれるコンストラクターも提供する必要があることに注意してください。

カスタム例外を定義するために必要なのはこれだけです。

次に、この例でカスタム例外を使用する方法を見てみましょう。

try (Scanner file = new Scanner(new File(fileName))) {
    if (file.hasNextLine())
        return file.nextLine();
} catch (FileNotFoundException e) {
    if (!isCorrectFileName(fileName)) {
        throw new IncorrectFileNameException("Incorrect filename : " + fileName );
    }
    //...
}

カスタム例外を作成して使用したので、ユーザーは正確な例外が何であるかを知ることができます。

これで十分ですか? その結果、例外の根本原因を失っています。

これを修正するために、java.lang.Throwableパラメーターをコンストラクターに追加することもできます。 このようにして、ルート例外をメソッド呼び出しに渡すことができます。

public IncorrectFileNameException(String errorMessage, Throwable err) {
    super(errorMessage, err);
}

これで、 IncorrectFileNameException が、例外の根本原因とともに使用されます。

try (Scanner file = new Scanner(new File(fileName))) {
    if (file.hasNextLine()) {
        return file.nextLine();
    }
} catch (FileNotFoundException err) {
    if (!isCorrectFileName(fileName)) {
        throw new IncorrectFileNameException(
          "Incorrect filename : " + fileName , err);
    }
    // ...
}

これが、カスタム例外を、発生元の根本原因を失うことなく使用できる方法です。

4. カスタムのチェックされていない例外

同じ例で、ファイル名に拡張子が含まれていない場合は、カスタム例外が必要であると想定します。

この場合、このエラーは実行時にのみ検出されるため、前の例外と同様のカスタムのチェックされていない例外が必要になります。

カスタムのチェックされていない例外を作成するには、java.lang.RuntimeExceptionクラスを拡張する必要があります

public class IncorrectFileExtensionException 
  extends RuntimeException {
    public IncorrectFileExtensionException(String errorMessage, Throwable err) {
        super(errorMessage, err);
    }
}

このようにして、この例では、このカスタムのチェックされていない例外を使用できます。

try (Scanner file = new Scanner(new File(fileName))) {
    if (file.hasNextLine()) {
        return file.nextLine();
    } else {
        throw new IllegalArgumentException("Non readable file");
    }
} catch (FileNotFoundException err) {
    if (!isCorrectFileName(fileName)) {
        throw new IncorrectFileNameException(
          "Incorrect filename : " + fileName , err);
    }
    
    //...
} catch(IllegalArgumentException err) {
    if(!containsExtension(fileName)) {
        throw new IncorrectFileExtensionException(
          "Filename does not contain extension : " + fileName, err);
    }
    
    //...
}

5. 結論

カスタム例外は、ビジネスロジックに関連する特定の例外を処理する必要がある場合に非常に役立ちます。 適切に使用すると、例外処理とロギングを改善するための実用的なツールとして機能します。

この記事で使用されている例のコードは、GitHubから入手できます。