TRY-CATCH の使用法
エラー (特に予期しないエラー) 発生時のコードの動作を管理することをエラー処理といいます。エラー処理には、以下のオペレーションが含まれます。
-
エラーの原因となる条件の修正
-
エラー発生後に動作を再開させるための処理の実行
-
実行フローの変更
-
エラーに関する情報のログ記録
InterSystems IRIS® データ・プラットフォームは、エラー処理のために TRY-CATCH メカニズムをサポートします。古いアプリケーションから移行されたコードでは、従来のエラー処理が行われる場合があります。これは引き続き全面的にサポートされていますが、新しいアプリケーションで使用することを意図したものではありません。
%Status の処理についても参照してください。こちらは厳密にはエラー処理ではありません。通常、ステータスの処理は TRY ブロック内で完結します。
概要
TRY-CATCH を使用すると、それぞれが TRY ブロックと呼ばれる区切られたコードのブロックを作成できます。TRY ブロック中にエラーが発生した場合、TRY ブロックに関連付けられた、例外処理のコードを含む CATCH ブロックに制御が渡されます。TRY ブロックには THROW コマンドを含めることもできます。これらのコマンドはそれぞれ、TRY ブロック内から明示的に例外を発行し、実行を CATCH ブロックに移します。
最も基本的な形式でこのメカニズムを使用するには、ObjectScript コード内に TRY ブロックを含めます。このブロック内で例外が発生する場合、関連付けられた CATCH ブロック内のコードが実行されます。TRY-CATCH ブロックの形式は以下のとおりです。
TRY {
protected statements
} CATCH [ErrorHandle] {
error statements
}
further statements
以下はその説明です。
-
TRY コマンドは、中括弧で囲まれた ObjectScript のコード文を識別します。TRY は、引数を取りません。このコード・ブロックは、構造化された例外処理のための保護されたコードです。TRY ブロック内で例外が発生した場合、InterSystems IRIS は例外プロパティ (oref.Name、oref.Code、oref.Data、oref.Location)、$ZERROR、および $ECODE を設定し、CATCH コマンドによって識別される、例外ハンドラに実行を移します。これは、例外のスローとして知られています。
-
protected statements は、通常の実行の一部である、ObjectScript 文です。(これらの文には、THROW コマンドへの呼び出しを含めることができます。このシナリオについては、以下のセクションで説明します。)
-
CATCH コマンドは、例外ハンドラを定義します。これは、TRY ブロックで例外が発生したときに実行されるコードのブロックです。
-
ErrorHandle 変数は、例外オブジェクトへのハンドルです。これは、InterSystems IRIS が実行時エラーに対して生成した例外オブジェクト、または THROW コマンド (以下のセクションで説明します) の呼び出しにより明示的に発行された例外オブジェクトのいずれかとなります。
-
error statements は、例外が発生したときに呼び出される ObjectScript 文です。
-
further statements は、例外がない場合に protected statements の実行の後に続く、または例外が発生して CATCH ブロックから制御が渡される場合に error statements の実行の後に続く、ObjectScript 文です。
protected statements の実行中のイベントに応じて、以下のイベントのいずれかが発生します。
-
エラーが発生しない場合、CATCH ブロックの外側に表示される further statements で実行が続行します。
-
エラーが発生する場合、制御が CATCH ブロックに渡され、error statements が実行されます。実行は、CATCH ブロックの内容によって異なります。
-
CATCH ブロックに THROW コマンドまたは GOTO コマンドが含まれている場合、指定された場所に制御が直接移動します。
-
CATCH ブロックに THROW コマンドまたは GOTO コマンドが含まれていない場合、CATCH ブロックから制御が渡され、further statements で実行が続行します。
-
TRY-CATCH と一緒に THROW を使用する
InterSystems IRIS は、実行時エラーの発生時に暗黙的な例外を発行します。明示的な例外を発行するには、THROW コマンドを使用できます。THROW コマンドは、TRY ブロックから CATCH 例外ハンドラへ実行を移します。THROW コマンドの構文は以下のとおりです。
THROW expression
expression は、例外処理のために InterSystems IRIS に用意されている %Exception.AbstractExceptionOpens in a new tab クラスから継承するクラスのインスタンスです。%Exception.AbstractExceptionOpens in a new tab の詳細は、以下のセクションを参照してください。
TRY/CATCH ブロックと THROW を一緒に発行する場合の形式は以下のとおりです。
TRY {
protected statements
THROW expression
protected statements
}
CATCH exception {
error statements
}
further statements
ここで、THROW コマンドは明示的に例外を発行します。TRY-CATCH ブロックの他の要素については、前のセクションで説明しています。
THROW の動作は、スローが発生する場所と THROW の引数によって異なります。
-
TRY ブロック内の THROW は、CATCH ブロックに制御を渡します。
-
CATCH ブロック内の THROW は、実行スタックの制御を次のエラー・ハンドラに渡します。例外が %Exception.SystemException オブジェクトの場合、次のエラー・ハンドラは、どのタイプ (CATCH または従来のエラー処理) でもかまいません。それ以外の場合は、CATCH による例外処理が必要となります。そうしないと、<NOCATCH> エラーがスローされます。
引数付きの THROW のために、制御が CATCH ブロックに渡される場合、ErrorHandle には引数からの値が含まれています。システム・エラーのために制御が CATCH ブロックに渡される場合、ErrorHandle は %Exception.SystemExceptionOpens in a new tab オブジェクトです。ErrorHandle が指定されていない場合、制御が CATCH ブロックに渡された理由が示されません。
例えば、以下のように 2 つの数字を除算するコードがあるとします。
div(num,div) public {
TRY {
SET ans=num/div
} CATCH errobj {
IF errobj.Name="<DIVIDE>" { SET ans=0 }
ELSE { THROW errobj }
}
QUIT ans
}
0 による除算エラーが発生すると、このコードは結果として 0 を返すように特別に設計されています。 この他のエラーの場合、THROW はスタック上のエラーを次のエラー・ハンドラに送信します。
$$$ThrowOnError および $$$ThrowStatus マクロの使用法
InterSystems IRIS は、例外処理で使用するために、マクロを提供します。これらのマクロは、呼び出されると CATCH ブロックに例外オブジェクトをスローします。
以下の例は、%Prepare() メソッドによりエラー・ステータスが返されると、$$$ThrowOnError マクロを呼び出します。
#include %occStatus
TRY {
SET myquery = "SELECT TOP 5 Name,Hipness,DOB FROM Sample.Person"
SET tStatement = ##class(%SQL.Statement).%New()
SET status = tStatement.%Prepare(myquery)
$$$ThrowOnError(status)
WRITE "%Prepare succeeded",!
RETURN
}
CATCH sc {
WRITE "In Catch block",!
WRITE "error code: ",sc.Code,!
WRITE "error location: ",sc.Location,!
WRITE "error data:",$LISTGET(sc.Data,2),!
RETURN
}
以下の例は、%Prepare() メソッドにより返されたエラー・ステータスの値をテストした後に$$$ThrowStatus を呼び出します。
#include %occStatus
TRY {
SET myquery = "SELECT TOP 5 Name,Hipness,DOB FROM Sample.Person"
SET tStatement = ##class(%SQL.Statement).%New()
SET status = tStatement.%Prepare(myquery)
IF ($System.Status.IsError(status)) {
WRITE "%Prepare failed",!
$$$ThrowStatus(status) }
ELSE {WRITE "%Prepare succeeded",!
RETURN }
}
CATCH sc {
WRITE "In Catch block",!
WRITE "error code: ",sc.Code,!
WRITE "error location: ",sc.Location,!
WRITE "error data:",$LISTGET(sc.Data,2),!
RETURN
}
詳細は、"システム・マクロ" を参照してください。
%Exception.SystemException と %Exception.AbstractException クラスの使用
InterSystems IRIS は、例外処理で使用するために、%Exception.SystemExceptionOpens in a new tab クラスと %Exception.AbstractExceptionOpens in a new tab クラスを提供します。%Exception.SystemExceptionOpens in a new tab は %Exception.AbstractExceptionOpens in a new tab クラスから継承しており、システム・エラーに使用されます。カスタム・エラーの場合、%Exception.AbstractExceptionOpens in a new tab から継承するクラスを作成します。%Exception.AbstractExceptionOpens in a new tab には、エラーの名前や発生した場所などのプロパティが含まれます。
システム・エラーが TRY ブロック内でキャッチされると、システムは %Exception.SystemExceptionOpens in a new tab クラスの新しいインスタンスを作成し、そのインスタンス内にエラー情報を配置します。アプリケーション・プログラマは、カスタム例外をスローするとき、オブジェクトにエラー情報を入れる責任があります。
例外オブジェクトには、以下のプロパティがあります。
-
Name — <UNDEFINED> などのエラー名。
-
Code — エラー番号
-
Location — エラーの label+offset^routine の場所
-
Data — エラーによって報告される任意の追加データ (エラーの原因となる項目の名前など)
TRY-CATCH を使用する際の他の考慮事項
TRY-CATCH ブロックを使用する際に発生する可能性がある状況を、以下に説明します。
TRY-CATCH ブロック内での QUIT
TRY または CATCH ブロック内の QUIT コマンドは、TRY-CATCH ブロック全体の後で、ブロックから次の文に制御を渡します。
TRY-CATCH と実行スタック
TRY ブロックは、実行スタックで新しいレベルを導入しません。つまり、NEW コマンドのアクセス範囲境界ではありません。error statements は、そのエラーと同じレベルで実行されます。この結果として、protected statements 内に DO コマンドがあり、DO のターゲットも protected statements 内にある場合には、予期しない結果が発生する可能性があります。このような場合には、$ESTACK 特殊変数が、相対的な実行レベルに関する情報を提供できます。
従来のエラー処理で TRY-CATCH を使用する
TRY-CATCH エラー処理は、実行スタックの異なるレベルで使用される $ZTRAP エラー・トラップと互換性があります。例外は、$ZTRAP を TRY 節の protected statements 内で使用できないことです。THROW コマンドでは、ユーザ定義のエラーは TRY-CATCH のみに制限されます。ZTRAP コマンドを使用したユーザ定義のエラーは、任意のタイプのエラー処理で使用できます。