05/07/25 1:45 am
JDK1.5(=J2SE 5.0)ではだいぶ標準ライブラリも拡張されてきた。サードパーティのライブラリに頼らずとも多少書き換えれば重宝する。JDK1.3の時代までは例外の中に例外を含めることが出来なかった。これは何を意味するかというと、例外をcatchし何かしらの例外に詰め替えて、throwsし続けると、元の例外の情報がそのままでは、なくなるという事である。SQLExceptionなどはその場で対処するため問題にならないが、フレームワークを開発する場合は、業務では理解できない例外はフレームワークへthrowしてしまえば後は解決できてしまうという構造が望ましい。つまり業務アプリは、例外設計など知らない技術者も実装するからである。
今回は、Jakarta Commons-Lang(英語)をつかって、「例外チェーン」の確認、使い方などを調べてみた。触ってみた感じでは、JDK1.4以降であれば素直に標準の例外機能で問題ないと思う。便利だとおもうのは、入れ子になった例外をメソッド名などで検索できる事ぐらいだ。
それと、Commons-Langのソースコードは綺麗でボリュームも少ないので標準ライブラリのソースコードと比較したりすると非常に勉強になると感じた。例外チェーンの仕組みよりも、Commons-Langのdelegateの仕方が可読性がよく、オブジェクト指向設計としてまとまっていた。またJUnitでリファクタリングしているのを見て、Apache Software Foundationも大規模なベンダーツールよりも、Subversion,JUnitなど基礎部分となる管理ツールを使っているのがシステム開発の参考になった。
この記事にたどり着いた方は是非、自分に必要なものを調べる際はソースコードを入手して学習して欲しい。
それと、面倒なので日本語は書かない。ソースコードを読んでください。
/*
* $Id: ExceptionUtilSample.java 905 2005-07-24 16:24:14Z s-okita $
*
* Copyright 2005 satoshiokita. All rights reserved.
*/
package org.oklab.apache.commons.lang;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.commons.lang.exception.NestableException;
/**
* 実行サンプル
* @author satoshiokita
*/
public class ExceptionUtilSample {
public static void main(String[] args) {
execute();
}
protected static void execute() {
try {
NestableExceptionSample3.a();
} catch (java.lang.RuntimeException e) {
// 非チェック例外
} catch (java.lang.Exception e) {
// 非チェック例外以外(大体はjava.lang.RuntimeException)をcatchする。
// チェック例外
// EceptionUtilsの各メソッドをテストしている
// ここまでは、メソッドの抽出をしている
printCause(e);
outputAllStackTrace(e);
printCauseRoot(e);
printStackAndStackFrame(e);
printChainException(e);
printStackLists(e);
// ここからは、まだメソッドの抽出をしていないもの
System.out.println("大元の原因を表示");
ExceptionUtils.printRootCauseStackTrace(e);
System.out.println("大元の原因をストリームに表示");
ExceptionUtils.printRootCauseStackTrace(e, System.err);
parseStackStructure(e);
nestableTest(e);
searchThrowable(e);
} catch (java.lang.Error e) {
// システムエラー
}
}
private static void searchThrowable(java.lang.Exception e) {
System.out.println("例外を探す検索条件としてmethod名をつけられる。");
String [] methods = { "c" };
Throwable z = ExceptionUtils.getCause(e, methods);
System.out.println(z.getMessage());
}
private static void nestableTest(java.lang.Exception e) {
System.out.println(ExceptionUtils.isNestedThrowable(e));
try {
throw new Exception("hogehoge!!");
} catch (Exception e1) {
System.out.println(ExceptionUtils.isNestedThrowable(e1));
}
}
private static void parseStackStructure(java.lang.Exception e) {
System.out.println("例外がStack構造のどこにあるか分かる");
int result = ExceptionUtils.indexOfThrowable(e, NullPointerException.class);
System.out.println("result=" + result);
int result2 = ExceptionUtils.indexOfThrowable(e, NestableException.class);
System.out.println("result2=" + result2);
int result3 = ExceptionUtils.indexOfThrowable(e, Exception.class);
System.out.println("result3=" + result3);
}
private static void printCauseRoot(java.lang.Exception e) {
System.out.println("最も上位の例外クラスを取得する");
System.out.println(ExceptionUtils.getRootCause(e));
}
private static void outputAllStackTrace(java.lang.Exception e) {
System.out.println("例外情報をすべて出力 JDK1.4と変わらない");
System.out.println(ExceptionUtils.getFullStackTrace(e));
}
private static void printStackLists(java.lang.Exception e) {
System.out.println("スタックのリスト表示");
Throwable [] expAry = ExceptionUtils.getThrowables(e);
for ( int i = 0 ; i < expAry.length; i++) {
(expAry[i]).printStackTrace();
}
}
private static void printChainException(java.lang.Exception e) {
System.out.println("// TraceCount 例外チェーンの中に例外クラスがいくつ入っているか");
System.out.println("count=" + ExceptionUtils.getThrowableCount(e));
}
private static void printStackAndStackFrame(java.lang.Exception e) {
System.out.println("// Cause Stacktrace");
String [] ary = ExceptionUtils.getRootCauseStackTrace(e);
for ( int i = 0; i < ary.length; i++) {
System.out.println(ary[i]);
}
System.out.println("// StackFrames?");
String [] frames = ExceptionUtils.getStackFrames(e);
for ( int i = 0; i < frames.length; i++) {
System.out.println(frames[i]);
}
}
private static void printCause(java.lang.Exception e) {
System.out.println("// 原因例外の取り出し");
System.out.println(e.getMessage());
Throwable c1 = ExceptionUtils.getCause(e);
System.out.println(c1.getMessage());
Throwable c2 = ExceptionUtils.getCause(c1);
System.out.println(c2.getMessage());
}
}
例外をthrowしているテスト対象ソースコード
/*
* $Id: NestableExceptionSample3.java 905 2005-07-24 16:24:14Z s-okita $
*
* Copyright 2005 satoshiokita. All rights reserved.
*/
package org.oklab.apache.commons.lang;
import java.sql.SQLException;
import org.apache.commons.lang.exception.NestableException;
/**
* @author satoshiokita
*
* この生成されたコメントの挿入されるテンプレートを変更するため
* ウィンドウ > 設定 > Java > コード生成 > コードとコメント
*/
public class NestableExceptionSample3 {
public static void main(String[] args) {
try {
a();
} catch (java.lang.RuntimeException e) {
// 非チェック例外
e.printStackTrace();
} catch (java.lang.Exception e) {
// 非チェック例外以外(大体はjava.lang.RuntimeException)をcatchする。
// チェック例外
e.printStackTrace();
} catch (java.lang.Error e) {
// システムエラー
e.printStackTrace();
}
}
/**
*
*/
public static void a() throws Exception {
try {
b();
} catch (Exception e) {
throw new NestableException("foo", e);
}
}
/**
*
*/
private static void b() throws Exception {
try {
c();
} catch (Exception e) {
Exception tmp = new NestableException("bar", e);
throw tmp;
}
}
/**
*
*/
private static void c() {
throw new NullPointerException("exception message in c");
}
}