業務アプリケーションにおいてエラーが発生した場合には、
本提案は、さまざまなスキルの不特定多数のプログラマが盲目的に従うことで一定の品質を実現しようというもので、個々の内容については必ずしも最適なものとはいえないことはやむなしとしています。
0除算やIOエラーなどのシステム的エラーは、特にそれに対するコードを書かなくても Java がそれぞれの例外を通知してくれます。
入力値の制限などのアプリケーション的エラーについては、その旨の例外を生成して通知(throw
)しなければなりません。
本提案では、アプリケーション的エラーに対する例外を1種類だけ設け、全てのアプリケーション的エラーに対してその例外を使うことにします。
アプリケーション例外:AppException
public class AppException extends RuntimeException
{
String detailInfo;
public AppException()
{
super();
}
public AppException(String message)
{
super(message);
}
}
if ( 0 == x ) {
throw new AppException("Illegal Parameter");
}
本提案では、上記の例外の他に、単に呼び元にエラーが発生したことだけを伝えるための例外を設けることにします。
この例外を検知した場合は、特に何もせず、そのままさらに呼び元に通知するだけとします。
そして、最終的な呼び元(大抵はイベントリスナ)で、メッセージを表示するなり、終了するなりします。
処理済み例外:ParsedException
public class ParsedException extends RuntimeException
{
public ParsedException()
{
super();
}
public ParsedException(String message)
{
super(message);
}
}
public void foo() throws ParsedException
{
try {
...
} catch (ParsedException e) {
throw e;
} catch (Exception e) {
throw new ParsedException(e.getMessage());
}
}
例外を検知(catch)せず呼び元にそのまま渡すことも無くはありませんが、通常は、例外はそのメソッド内で検知して、それに対する処理を行います。
そのとき、そのメソッドの処理全体をひとつの Try ブロックにして一括して例外を検知するのが普通です。
(勿論、必要な場合は、メソッドの呼出し単位やある程度まとまった処理の単位で検知する場合もあります。)
そこで、本提案では、
public void foo() throws ParsedException
{
try {
...
} catch (ParsedException e) {
throw e;
} catch (Exception e) {
throw new ParsedException(e.getMessage());
}
}
エラー発生のログとしては、
例外を検知したときに出力します。
呼出し経路を正しく戻っていくかを確認するために、処理済み例外を検知した場合も出力することにします。
エラーの詳細を出力したいときに出力します。(任意)
エラーの詳細がわかる箇所ということで、例外を検知したときではなく、エラーが発生した箇所で出力することになると思います。
システム的例外に対して出力したい場合は、その部分だけの try ブロックを設けて行うことになります。(後述のプログラム例参照。)
最初に例外を検知したときに1回だけ出力します。
public class MyClass
{
private static final String CLASS = "MyClass";
public void foo(int x) throws ParsedException
{
private final String METHOD = "foo";
try {
// パラメータ・エラー・チェック(詳細情報 x=0 を出力)
if ( 0 == x ) {
LogWriter.doWrite(CLASS, METHOD, "Illegal Parameter", "x=0");
throw new AppException("Illegal Parameter");
}
// 特にエラー詳細を出力したい場合(詳細情報 x を出力)
try {
uoo(x);
} catch (Exception e) {
LogWriter.doWrite(CLASS, METHOD, e.getMessage(), "x="+new Integer(x).toString());
throw e;
}
// 通常の例外処理をする場合
uoo(x);
} catch (ParsedException e) {
LogWriter.doWrite(CLASS, METHOD, e.getMessage());
throw e;
} catch (Exception e) {
LogWriter.doWriteStackTrace(e);
LogWriter.doWrite(CLASS, METHOD, e.getMessage());
throw new ParsedException(e.getMessage());
}
}
public void boo(int x) throws ParsedException
{
private final String METHOD = "boo";
try {
foo(x);
} catch (ParsedException e) {
LogWriter.doWrite(CLASS, METHOD, e.getMessage());
throw e;
} catch (Exception e) {
LogWriter.doWriteStackTrace(e);
LogWriter.doWrite(CLASS, METHOD, e.getMessage());
throw new ParsedException(e.getMessage());
}
}
public static void main(String[] args)
{
private final String METHOD = "main";
try {
boo(new Integer(args[0]).intValue());
} catch (ParsedException e) {
LogWriter.doWrite(CLASS, METHOD, e.getMessage());
System.out.println("Error occured !!");
} catch (Exception e) {
LogWriter.doWriteStackTrace(e);
LogWriter.doWrite(CLASS, METHOD, e.getMessage());
System.out.println("Error occured !!");
}
}
}
LogWriter
クラス は、そういうものが作ってあると思って下さい。foo()
に x=0
が渡された場合のログは、次のようになります。
Thu Aug 15 16:52:11 JST 2002: MyClass.foo() Illegal Parameter x=0
java.lang.Exception: Illegal Parameter
at MyClass.foo(MyClass.java:53)
at MyClass.boo(MyClass.java:75)
at MyClass.main(MyClass.java:92)
Thu Aug 15 16:52:11 JST 2002: MyClass.foo() Illegal Parameter
Thu Aug 15 16:52:11 JST 2002: MyClass.boo() Illegal Parameter
Thu Aug 15 16:52:11 JST 2002: MyClass.main() Illegal Parameter
操作者への通知や回復処理,終了処理は、原則として、最終的な呼び元(大抵はイベントリスナ)で行うこととします。