THROW (ObjectScript)
構文
THROW oref THROW:pc oref
引数
引数 | 説明 |
---|---|
pc | オプション — 後置条件式。 |
oref | オプション — 例外ハンドラへスローされるオブジェクト参照 (OREF)。 オプションですが、指定することを強くお勧めします。 |
説明
THROW コマンドは明示的に例外をスローします。例外は、システム・エラー、%Status 例外、またはユーザ定義の例外です。この例外は、%Exception.AbstractExceptionOpens in a new tab オブジェクトから継承するオブジェクト参照 (OREF) としてスローされます。THROW コマンドは、この例外を次の例外ハンドラへスローします。
THROW oref の使用には、2 つの方法があります。
-
TRY/CATCH : THROW oref を使用して、TRY のコード・ブロック内から例外を明示的に通知し、TRY ブロックから対応する CATCH ブロックの例外ハンドラに実行を渡します。
-
その他の例外ハンドラ : THROW oref を使用して、TRY ブロック外において例外を明示的に通知します。これにより、現在の例外ハンドラ ($ZTRAP など) がトリガされます。oref は $THROWOBJ 特殊変数から取得できます。
システム・エラー
InterSystems IRIS は、未定義の変数を参照するなどの実行時エラーが発生したときにシステム・エラーを発行します。システム・エラーは %Exception.SystemExceptionOpens in a new tab オブジェクト参照を生成して、oref のプロパティである Code、Name、Location、Data、ならびに、$ZERROR および $ECODE 特殊変数を設定し、次のエラー・ハンドラに制御を渡します。このエラー・ハンドラは、CATCH 例外ハンドラ、または $ZTRAP あるいは $ETRAP エラー・ハンドラです。システム・エラーは暗黙的エラーであり、THROW を使用しません。
エラー・ハンドラ内において THROW を使用すると、システム・エラー・オブジェクトをさらに別のエラー・ハンドラにスローできます。これは信号再伝達システム・エラーと呼ばれます。
THROW は、実行スタックの制御を次のエラー・ハンドラに渡します。例外が %Exception.SystemExceptionOpens in a new tab オブジェクトである場合、次のエラー・ハンドラは CATCH、$ZTRAP または $ETRAP のいずれのタイプでもかまいません。 それ以外の場合、例外を処理するためには、CATCH である必要があります。そうでないと、<THROW> エラーが生成されます。
引数
oref
例外オブジェクトへの参照。これは %Exception.AbstractExceptionOpens in a new tab を継承する任意のクラスのインスタンスです。システム・エラーの例外オブジェクトは、クラス %Exception.SystemExceptionOpens in a new tab のインスタンスです。ユーザ指定の例外オブジェクトは、%Status 例外オブジェクト (%Exception.StatusExceptionOpens in a new tab)、一般的な例外オブジェクト (%Exception.General)、または SQL 例外オブジェクト (%Exception.SQLOpens in a new tab) のいずれかになります。ユーザ例外オブジェクトを作成してデータを入れるのは、プログラマの責任です。
OREFの詳細は、"OREF の基本" を参照してください。
TRY ブロックからの THROW
THROW oref は、TRY ブロックから対応する CATCH ブロックに発行できます。これにより、ユーザ定義の例外が明示的に通知されます。これにより、TRY ブロックから対応する CATCH ブロックに実行が渡されます。スローされた oref は、CATCH ブロックの exceptionvar 引数として設定されます。
引数付きの THROW を CATCH の例外ハンドラから発行するには、CATCH 以外の例外ハンドラにスローするか、または TRY ブロック (および関連する入れ子になった CATCH ブロック) を CATCH の例外ハンドラ内で入れ子にし、この入れ子になった TRY ブロックから THROW を発行します。
%Status 例外およびユーザ定義の例外
%Status 例外またはユーザ定義の例外をトラップするには、oref 引数として %Exception.AbstractExceptionOpens in a new tab オブジェクトに基づいたオブジェクトを指定します。例外クラスを定義してから、%New() を使用してそのクラスのインスタンスを作成し、例外情報を提供します。このタイプの例外は、CATCH 例外ハンドラで処理される必要があります。CATCH が存在しない場合、システムは <THROW> エラーを生成します。
ユーザ定義の例外では、$ZERROR の値も $ECODE の値も変更されません。これらの特殊変数のいずれかを使用するには、プログラムで SET コマンドを使用して、これらの変数を明示的に設定する必要があります。
一般的な例外
InterSystems IRIS は、THROW 引数として指定できる一般的な例外を提供します。これは %Exception.AbstractExceptionOpens in a new tab 抽象クラスの %Exception.GeneralOpens in a new tab サブクラスです。この使用法は、以下の例を参照してください。
TRY {
WRITE "In the TRY block",!!
SET mygenex = ##class(%Exception.General).%New("My exception","999",,
"My own special exception")
THROW mygenex
WRITE "This shouldn't display",!
}
CATCH stuff {
WRITE "In the CATCH block",!
WRITE stuff.Name,!
WRITE stuff.Code,!
WRITE stuff.Data,!
WRITE "End of the CATCH block",!
RETURN
}
TRY ブロック外における THROW
THROW を TRY ブロック外から発行すると、InterSystems IRIS によって <THROW> エラー "<THROW>+3^myprog *%Exception.General MyErr 999 My user-defined error" が生成されます。この THROW の使用は、エラーの再通知に役立ちます。
THROW で指定されるオブジェクト参照 (oref) は、$THROWOBJ 特殊変数で保存されます。例 : 9@%Exception.General。$THROWOBJ 値は、次の正常な THROW 処理、または SET $THROWOBJ="" によってクリアされます。
以下の例では、THROW は $ZTRAP の例外ハンドラに例外をスローします。
MainRou
WRITE "In the Main Routine",!!
SET $ZTRAP=^ErrRou
SET mygenex = ##class(%Exception.General).%New("My exception","999",,
"My own special exception")
THROW mygenex
WRITE "This shouldn't display",!
RETURN
ErrRou
WRITE "In $ZTRAP",!
SET oref=$THROWOBJ
SET $THROWOBJ=""
WRITE oref.Name,!
WRITE oref.Code,!
WRITE oref.Data,!
WRITE "End of $ZTRAP",!
RETURN
引数なしの THROW
引数なしの THROW は、現在のシステム・エラーを再び信号で送り、次の例外ハンドラへ制御を渡します。現在のシステム・エラーは、$ZERROR 特殊変数によって参照されるエラーです。したがって、引数なしの THROW はコマンド ZTRAP $ZERROR と同等です。
どのシステム・エラーが現在のシステム・エラーであるかは変更されることがあるため、引数なしの THROW の使用はお勧めできません。例えば、エラー・ハンドラが $ZERROR 値を変更した場合、または、エラー・ハンドラ自体がシステム・エラーを生成した場合にこれが発生する可能性があります。そのため、THROW oref を使用して、次の例外ハンドラへスローされるシステム・エラーを明示的に指定することをお勧めします。
例
以下の例では、%Exception.GeneralOpens in a new tab クラスのインスタンスを使用してユーザ定義の例外をスローします。ここでは、後置条件付き構文で THROW を使用する方法を示しています。この例では、Exceptions メソッドを呼び出し、引数として 5 以上の数を渡すと、例外がスローされて catch ブロックの WRITE 文が実行されます。
ClassMethod Exceptions(x As %Integer)
{
set ex = ##class(%Exception.General).%New()
set ex.Name = "Demo Exception",
ex.Code = 100000,
ex.Data = "Tutorial Example"
try {
write !, "Hello!,
throw:(x >= 5) ex // throw the exception }
catch err {
write !, "x: ", ?20, x,
!, "Error name: ", ?20, err.Name,
!, "Error code: ", ?20, err.Code,
!, "Error location: ", ?20, err.Location,
!, "Additional data: ", ?20, err.Data, !
}
write !, "Finished!"
}
以下の例では、InterSystems IRIS のエラー名が山括弧で囲まれ、これらの例が Web ブラウザから実行されるので、$ZCVT(myerr.Name,"O","HTML") が使用されます。多くの別のコンテキストでは、myerr.Name は必要な値を返します。
以下の例では、TRY ブロックで誕生日が生成されます。未来の日付の誕生日が生成された場合、THROW の使用により一般的な例外が発行され、ユーザ定義の例外の OREF が汎用 CATCH ブロックに渡されます。(例外をスローする日付を生成するために、この例を複数回実行する必要がある場合があります)
TRY {
WRITE "In the TRY block",!
SET badDOB=##class(%Exception.General).%New("<BAD DOB>","999",,"Birth date is in the future")
FOR x=1:1:20 { SET rndDOB = $RANDOM(7)_$RANDOM(10000)
IF rndDOB > $HOROLOG { WRITE !,"Birthdate ",$ZDATE(rndDOB,1,,4)," is invalid"
THROW badDOB }
ELSE { WRITE "Birthdate ",$ZDATE(rndDOB,1,,4)," is valid",! }
}
}
CATCH err {
WRITE !,"In the CATCH block"
WRITE !,"Error code=",err.Code
WRITE !,"Error name=",$ZCVT(err.Name,"O","HTML")
WRITE !,"Error data=",err.Data
RETURN
}
以下の例では、ユーザ定義の引数を使用した 2 つの THROW コマンドのいずれかを発行できます。$RANDOM は、どの THROW を発行するか (ランダムな値 0 または 1)、または THROW を発行しないか (ランダムな値 2) を選択します。ブロックの実行が RETURN コマンドで終了しない限りは、コードの実行は TRY / CATCH ブロックの後に続行されます。
TRY {
SET errdatazero="this is the zero error"
SET errdataone="this is the one error"
/* Error Randomizer */
SET test=$RANDOM(3)
WRITE "Error test is ",test,!
IF test=0 {
WRITE !,"Throwing exception 998",!
THROW ##class(Sample.MyException).%New("TestZeroError",998,,errdatazero)
THROW myvar
}
ELSEIF test=1 {
WRITE !,"Throwing exception 999",!
THROW ##class(Sample.MyException).%New("TestOneError",999,,errdataone)
}
ELSE { WRITE !,"No THROW error this time" }
}
CATCH exp {
WRITE !,"This is the exception handler"
WRITE !,"Error code=",exp.Code
WRITE !,"Error name=",exp.Name
WRITE !,"Error data=",exp.Data
RETURN
}
WRITE !!,"Execution after TRY block continues here"
以下の例は、システム・エラーが発生したときの THROW の使用法を示しています。THROW は、一般的に、システム・エラーを別のハンドラに転送するために CATCH 例外ハンドラで使用されます。これは、システム・エラーが予期しないタイプのシステム・エラーを受け取ったときに行われる可能性があります。これを行う場合、TRY ブロック (および対応する CATCH ブロック) を CATCH ブロック内に入れ子にする必要があることに注意してください。これは、入れ子になった CATCH ブロックにシステム・エラーを THROW するために使用されます。以下の例でこれを示します。Calculate を呼び出して除算演算を実行して、その答えを返します。考えられる結果は 3 種類です。その 1 番目として、y が任意のゼロ以外の数値の場合、除算演算は成功し、CATCH ブロック・コードは実行されません。2 番目として、y がゼロ (または非数値文字列) の場合、除算演算では、ゼロでの除算が試みられ、その CATCH ブロックにシステム・エラーがスローされます。これは、このエラーを “修正して” 0 値を返す calcerr 例外ハンドラによって捕捉されます。3 番目として、y が定義されていない場合 (NEW y)、calcerr は予期しないシステム・エラーを捕捉して、このエラーを myerr 例外ハンドラへスローします。この 3 つの結果を示すために、このサンプル・プログラムでは $RANDOM を使用して除数 (y) を設定しています。
Randomizer
SET test=$RANDOM(3)
IF test=0 { SET y=0 }
ELSEIF test=1 { SET y=7 }
ELSEIF test=2 { NEW y }
/* Note: if test=2, y is undefined */
Main
SET x=4
TRY {
SET result=$$Calculate(x,y)
WRITE !,"Calculated value=",result
}
CATCH myerr {
WRITE !,"this is the exception handler"
WRITE !,"Error code=",myerr.Code
WRITE !,"Error name=",$ZCVT(myerr.Name,"O","HTML")
WRITE !,"Error data=",myerr.Data
}
QUIT
Calculate(arg1,arg2) PUBLIC {
TRY {
SET answer=arg1/arg2
}
CATCH calcerr {
WRITE "In the CATCH Block",!
TRY {
IF calcerr.Name="<DIVIDE>" {
WRITE !,"handling zero divide error"
SET answer=0 }
ELSE { THROW calcerr }
RETURN
}
CATCH {
WRITE "Unexpected error",!
WRITE "Error name=",$ZCVT(myerr.Name,"O","HTML"),!
}
}
QUIT answer
}