Javaにおける連鎖例外

1概要

この記事では、 Exception とは何かについて非常に簡単に説明し、Javaでの連鎖例外について説明します。

簡単に言うと、 exception はプログラムの実行の通常の流れを妨げるイベントです。それでは、例外からより良いセマンティクスを引き出すために、例外を連鎖させる方法を正確に見てみましょう。

2連鎖例外

連鎖 Exception は、ある例外がアプリケーション内で別の Exception を引き起こす状況を識別するのに役立ちます。

  • たとえば、ゼロで除算しようとしたが ArithmeticException ** をスローするが、実際の例外の原因は除数をゼロにしたI/Oエラーだった。呼び出し元は Exception の実際の原因について知りません。そのような状況では、連鎖 Exception が使用されます。

この概念はJDK 1.4で導入されました。

Javaで連鎖例外がどのようにサポートされているかを見てみましょう。

3 Throwable クラス

Throwableクラスには、連鎖例外をサポートするためのコンストラクタとメソッドがいくつかあります。まず、コンストラクタを見てみましょう。

  • Throwable(Throwable cause) Throwable には単一のパラメータがあります。

これは Exception の実際の原因を指定します。

  • Throwable(String desc、Throwable cause) このコンストラクタ

Exception の実際の原因を含む Exception 記述も受け入れます。

次に、このクラスが提供するメソッドを見てみましょう。

  • getCause() method - このメソッドは実際の原因を返す

現在の Exception に関連付けられています。

  • initCause() method - 呼び出しで根本的な原因を設定する

例外

4例

それでは、独自の Exception 記述を設定し、連鎖した Exception をスローする例を見てみましょう。

public class MyChainedException {

    public void main(String[]args) {
        try {
            throw new ArithmeticException("Top Level Exception.")
              .initCause(new IOException("IO cause."));
        } catch(ArithmeticException ae) {
            System.out.println("Caught : " + ae);
            System.out.println("Actual cause: "+ ae.getCause());
        }
    }
}

ご想像のとおり、これは次のことにつながります。

Caught: java.lang.ArithmeticException: Top Level Exception.
Actual cause: java.io.IOException: IO cause.

5なぜ連鎖例外なのか?

ログを読みやすくするために、例外を連鎖させる必要があります。 2つの例を書きましょう。まず例外を連鎖させずに、次に連鎖例外を用いて後で、両方のケースでログがどのように動作するかを比較します。

はじめに、一連の例外を作成します。

class NoLeaveGrantedException extends Exception {

    public NoLeaveGrantedException(String message, Throwable cause) {
        super(message, cause);
    }

    public NoLeaveGrantedException(String message) {
        super(message);
    }
}

class TeamLeadUpsetException extends Exception {
   //Both Constructors
}

それでは、コード例で上記の例外の使用を始めましょう。

** 5.1. チェーニングなし

カスタム例外を連鎖せずにプログラム例を書いてみましょう。

public class MainClass {

    public void main(String[]args) throws Exception {
        getLeave();
    }

    void getLeave() throws NoLeaveGrantedException {
        try {
            howIsTeamLead();
        } catch (TeamLeadUpsetException e) {
            e.printStackTrace();
            throw new NoLeaveGrantedException("Leave not sanctioned.");
        }
    }

    void howIsTeamLead() throws TeamLeadUpsetException {
        throw new TeamLeadUpsetException("Team Lead Upset");
    }
}

上記の例では、ログは次のようになります。

com.baeldung.chainedexception.exceptions.TeamLeadUpsetException:
  Team lead Upset
    at com.baeldung.chainedexception.exceptions.MainClass
      .howIsTeamLead(MainClass.java:46)
    at com.baeldung.chainedexception.exceptions.MainClass
      .getLeave(MainClass.java:34)
    at com.baeldung.chainedexception.exceptions.MainClass
      .main(MainClass.java:29)
Exception in thread "main" com.baeldung.chainedexception.exceptions.
  NoLeaveGrantedException: Leave not sanctioned.
    at com.baeldung.chainedexception.exceptions.MainClass
      .getLeave(MainClass.java:37)
    at com.baeldung.chainedexception.exceptions.MainClass
      .main(MainClass.java:29)

5.2. チェーン付き

次に、カスタム例外を連鎖させた例を書きましょう。

public class MainClass {
    public void main(String[]args) throws Exception {
        getLeave();
    }

    public getLeave() throws NoLeaveGrantedException {
        try {
            howIsTeamLead();
        } catch (TeamLeadUpsetException e) {
             throw new NoLeaveGrantedException("Leave not sanctioned.", e);
        }
    }

    public void howIsTeamLead() throws TeamLeadUpsetException {
        throw new TeamLeadUpsetException("Team lead Upset.");
    }
}

最後に、連鎖例外で取得されたログを見てみましょう。

Exception in thread "main" com.baeldung.chainedexception.exceptions
  .NoLeaveGrantedException: Leave not sanctioned.
    at com.baeldung.chainedexception.exceptions.MainClass
      .getLeave(MainClass.java:36)
    at com.baeldung.chainedexception.exceptions.MainClass
      .main(MainClass.java:29)
Caused by: com.baeldung.chainedexception.exceptions
  .TeamLeadUpsetException: Team lead Upset.
    at com.baeldung.chainedexception.exceptions.MainClass
  .howIsTeamLead(MainClass.java:44)
    at com.baeldung.chainedexception.exceptions.MainClass
  .getLeave(MainClass.java:34)
    ... 1 more

表示されたログを簡単に比較して、連鎖した例外によってログがきれいになると結論付けることができます。

前の投稿:セレニティBDDの紹介
次の投稿:Spring Boot CLIの紹介