Javaの例外チェイン
Javaの例外チェイン(Chained Exception)とは、例外情報を伝播していくための機能です。1つ目の例外がスローされ、1つ目の例外をキャッチしたあとに、さらに例外を投げていくときに、2つ目の例外の情報に1つ目の例外の情報を付加してスローします。このように、例外をキャッチするために、前の例外の情報を追加して、新しく例外を投げ続けていく場合に、最終的にエラー処理を実行するところに、エラーを伝搬する、といったことが可能になります。ここでは、例外チェインのスローの仕方を説明します。
読み方
- 例外チェイン
- れいがい ちぇいん
目次
概要
例外を受け取ったときに、新しい例外を送出(throw)したくなります。しかしながら、新しい例外でオリジナルの例外の情報を伝達したいときには、例外チェインで実現できます。
これは、簡単に実現できます。受け取った例外を新しい例外のコンストラクタにセットしてスローするだけです。
例外の情報を失う例 Exception1
まず最初に、例外チェインなしに、例外をキャッチしたときに、新しい例外を投げるコードを見てみましょう。
public class Exception1 { public static void main(String[] args) { try { try { throw new Exception("One"); // 1つ目の例外 } catch (Exception e) { // 1つ目のキャッチ throw new Exception("Two"); // 2つ目の例外 } } catch (Exception e) { // 2つ目のcatch e.printStackTrace(); } } }
上記のコードでは、1つ目の例外は、throwの直後のcatchによって受け取られます。その中で、さらにthrowをしています(2)。2つ目のキャッチでは、2回目の例外を受け取ります。
2回目のキャッチでは、2つ目の例外の情報しかないため、スタックトレースの結果は、以下の通りになります。
$ java Exception1 java.lang.Exception: Two at Exception1.main(Exception1.java:15)
このように、ただ、例外をキャッチして、新しく例外をスローしていると、例外の情報が伝達されず、結果的に、どこでなにが起きて、このエラーになったのか、分からなくなってしまうという問題があります。
例外チェインの簡単な例 Throwable1
前述した通り、例外チェインなしの例外処理では、例外の情報が失われるということがわかりました。
次に、例外チェインの例を見てみましょう。
ソースコード Throwable1.java
このコードは、例外チェインのためのサンプルです。
/* * Throwable1.java * Copyright (C) 2015 kaoru <kaoru@localhost> */ public class Throwable1 { public static void main(String[] args) { try { try { throw new Exception("One"); // 1つ目の例外 } catch (Exception e) { // 1つ目のキャッチ throw new Exception("Two", e); // 2つ目の例外 } } catch (Exception e) { // 2つ目のキャッチ e.printStackTrace(); } } }
1つ目の例外を1つ目のキャッチで受け取っています。「2つ目の例外」をスローするときに、Exceptionクラスのコンストラクタの第2引数に、「1つ目の例外」の例外を渡します。これにより、1つ目の例外を2つ目の例外に情報を入れて、スローすることができます。これを例外チェインといいます。
コンパイル
javac Throwable1.java
実行例
例外チェインにより、1つ目の例では、内側の例外が2つ目のキャッチに情報が伝達されませんでしたが、2つ目の Throwable1.java のコードでは、1つ目の例外の情報も含めて、2つ目のキャッチまで情報が伝達されていることが、以下の実行結果のスタックトレースからわかります。
$ java Throwable1 java.lang.Exception: Two at Throwable1.main(Throwable1.java:12) Caused by: java.lang.Exception: One at Throwable1.main(Throwable1.java:10)
例外チェインをSystem.out.printlnで表示した場合
public class Throwable1 { public static void main(String[] args) { try { try { throw new Exception("One"); // 1つ目の例外 } catch (Exception e) { // 1つ目のキャッチ throw new Exception("Two", e); // 2つ目の例外 } } catch (Exception e) { // 2つ目のキャッチ e.printStackTrace(); System.out.println("------"); System.out.println(e); // <--- ココ } } }
最後のprintlnでは、最後の例外のメッセージだけが表示されます。
$ java Throwable1 java.lang.Exception: Two at Throwable1.main(Throwable1.java:12) Caused by: java.lang.Exception: One at Throwable1.main(Throwable1.java:10) ------ java.lang.Exception: Two
短い例外チェインの例
少し短い例外チェインの例を見てみましょう。
ソースコード Throwable2.java
なにが違うかというと、2つ目の例外の引数が1つだけになっています。
/* * Throwable2.java * Copyright (C) 2015 kaoru <kaoru@localhost> */ public class Throwable2 { public static void main(String[] args) { try { try { throw new Exception("One"); // 1つ目の例外 } catch (Exception e) { // 1つ目のキャッチ throw new Exception(e); // 2つ目の例外 } } catch (Exception e) { // 2つ目のキャッチ e.printStackTrace(); } } }
コンパイル
javac Throwable2.java
実行例
このように、短い例外チェインの場合は、以下の様なスタックトレースになります。
$ java Throwable2 java.lang.Exception: java.lang.Exception: One at Throwable2.main(Throwable2.java:14) Caused by: java.lang.Exception: One at Throwable2.main(Throwable2.java:12)
関連項目
- Javaの例外チェイン
- Javaで独自例外クラスを自作する方法
ツイート