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
例
以下の例では、%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
}