Javaの連鎖例外
1. 概要
この記事では、Exceptionが何であるかを簡単に説明し、Javaでの連鎖例外について詳しく説明します。
簡単に言えば、exceptionは、プログラムの実行の通常の流れを妨げるイベントです。 ここで、例外を連鎖させて、例外からより良いセマンティクスを引き出す方法を正確に見てみましょう。
2. 連鎖例外
連鎖されたExceptionは、ある例外がアプリケーションで別のExceptionを引き起こす状況を特定するのに役立ちます。
For instance, consider a method which throws an ArithmeticExceptionはゼロで除算しようとしたためですが、実際の例外の原因はI / Oエラーであり、除数がゼロになりました。メソッドはArithmeticExceptionを呼び出し元にスローします。 呼び出し元は、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 –Exceptionを呼び出すことで根本的な原因を設定します。
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つの例を書いてみましょう。 1つは例外を連鎖せず、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.example.chainedexception.exceptions.TeamLeadUpsetException:
Team lead Upset
at com.example.chainedexception.exceptions.MainClass
.howIsTeamLead(MainClass.java:46)
at com.example.chainedexception.exceptions.MainClass
.getLeave(MainClass.java:34)
at com.example.chainedexception.exceptions.MainClass
.main(MainClass.java:29)
Exception in thread "main" com.example.chainedexception.exceptions.
NoLeaveGrantedException: Leave not sanctioned.
at com.example.chainedexception.exceptions.MainClass
.getLeave(MainClass.java:37)
at com.example.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.example.chainedexception.exceptions
.NoLeaveGrantedException: Leave not sanctioned.
at com.example.chainedexception.exceptions.MainClass
.getLeave(MainClass.java:36)
at com.example.chainedexception.exceptions.MainClass
.main(MainClass.java:29)
Caused by: com.example.chainedexception.exceptions
.TeamLeadUpsetException: Team lead Upset.
at com.example.chainedexception.exceptions.MainClass
.howIsTeamLead(MainClass.java:44)
at com.example.chainedexception.exceptions.MainClass
.getLeave(MainClass.java:34)
... 1 more
表示されたログを簡単に比較して、連鎖した例外がよりクリーンなログにつながると結論付けることができます。
6. 結論
この記事では、連鎖例外の概念について説明しました。
すべての例の実装はthe Github projectにあります。これはMavenベースのプロジェクトであるため、そのままインポートして実行するのは簡単です。