例外ハンドリング

CRSは、JavaScriptとほぼ同じようにtry…catchにより例外をハンドリングすることができます。

try … catch throw 文

try {
    実行文1
}
catch (e) {
    実行文2
}

tryブロックで囲まれた実行文1を実行し、その実行過程で例外が発生した場合、後続の実行文1にステートメント実行を中止し、実行文2に制御を移します。

catchステートメントの仮引数 e は、Exceptionオブジェクトが渡されます。 Exceptionオブジェクトのプロパティによりどのような例外が発生したか知ることができます。

e.category 例外を起こした機能の識別子
e.code 例外の種類
e.subCode 例外の補助的な種類
e.message 例外の内容
e.sourceUrl 例外が発生したスクリプトのURL
e.sourceLine 例外が発生したスクリプトの行番号
e.sourceCol 例外が発生したスクリプトの列番号

try {
    var a = foo1(1);
    var b = foo2(2);
    var c = foo3(3);
}
catch (e) {
    print("例外", e.Message, "が発生しました\n");
}

catchブロック内で、引数のないthrow文を実行するかcatch文で受け取ったExceptionオブジェクトをthrowすることにより、 catchが受け取った例外を上位のブロックにスローすることができます。

try {
    var a = foo1(1);
    var b = foo2(2);
    var c = foo3(3);
}
catch (e) {
    if (e.category == "SYS") {
        print("SYS例外", e.message, "が発生しました\n");
    } else {
        throw e;
    }
}

また、catchする例外を選択する場合、下記のように条件付きcatchコードを記述することが可能です。

try {
    var a = foo1(1);
    var b = foo2(2);
    var c = foo3(3);
}
catch SYS (e) {
    # e.category == "SYS"の例外のみが捕捉されます。
}
catch UserException:1 (e) {
    # e.category == "UserException", e.code == 1 の例外のみが捕捉されます。
}
catch UserException:2-3 (e) {
    # e.category == "UserException", e.code == 2, e.subCode == 3 の例外のみが捕捉されます。
}
catch Exp1 | Exp2:4 (e) {
    # e.category == "Exp1" または e.category == "Exp2", e.code == 4 の例外のみが捕捉されます。
}
catch(e) {
    # 上記以外の例外が捕捉されます。
    # このブロック(catch(e))を記述しない場合、例外は自動的に上位のブロックにスローされます。
}

try … finally文

try {
    実行文1
}
catch (e) {
    実行文2
}
finally {
    実行文3
}

または

try {
    実行文1
}
finally {
    実行文3
}

実行文1の実行過程で例外が発生した場合、対応するcatchブロックが存在する場合、(上記例では)実行文2に制御を移します。

対応するcatchブロックが存在しないか、catchブロックの終端まで実行した場合、実行文3に制御を移します。


finallyブロックを用いることで、例外の発生有無にかかわらず実行される処理を完結に記述することが可能です。


finally構文が実装されているJava言語と同じく、finallyブロックが適切に実行されるためにはcatchブロック内でreturnを行ってはいけません。

catchブロック内でreturnステートメントを実行した場合、catchブロックが紐付くfinallyブロック内の処理がスキップされます。

try {
    throw new Exception("app", 1, 1);
}
catch (e) {
    return; # catchブロック内でのreturn文呼び出しは行ってはいけません。
}
finally {
    # このブロック内の処理は実行されません。
}

try … catch の有効範囲

try … catch による例外ハンドリングは実行時のみ有効です。

Biz/Designerで生成されるCRSファイル全体をtryブロックに入れても、 イベントハンドラの実行により発生した例外は捕らえることができないことに注意してください。

try {  ←tryブロック開始
    Form form1 {
        Width = 100;
        Height = 100;
        :
        Function OnTouch(e) {
            :
            throw new Exception("app", 1, "test");
            :
        }
    }
} ← tryブロック終了
catch (e) {
    print(e.Message, "\n");

}

この例では、Form全体をtryブロックに入れていますが、このtryブロックはformの生成時に発生する例外は捕捉されますが、 Formの生成が終わるとtryブロックを抜けてしまうため、OnTouchイベントハンドラ内で発生する例外は捕らえることはできません。

OnTouchで発生する例外を捕らえるためには次のように記述します。

Form form1 {
    Width = 100;
    Height = 100;
    :
    Function OnTouch(e) {
        try {  ←tryブロック開始
            :
            throw new Exception("app", 1, 2, "test");
            :
        } ← tryブロック終了
        catch(e) {
            print(e.message, "\n");
        }
    }
}

ユーザ定義の例外

Exceptionオブジェクトを生成し、throw文に渡すことでアプリケーション固有の例外を発生させることができます。


function foo (a) {
    if (a == 0) {
        throw new Exception("SalesApp::Common::Utility", 5, 1, "引数が0です");
    }
    return 100 / a;
}

Exceptionオブジェクトのコンストラクタには、以下の値を渡します。


第1パラメータ:例外の種類を指定します。categoryプロパティの値となります。

第2パラメータ:例外コードを指定します。codeプロパティの値となります。

第3パラメータ:例外サブコードを指定します。subCodeプロパティの値となります。

第4パラメータ:説明文を指定します。messageプロパティの値となります。

グローバル例外ハンドラ

"//"(Rootオブジェクト)にonException関数を定義することで、catchされない全ての例外を捕捉して呼び出されます。

:
// {
    function onException(e) {
        messageBox("エラーが発生しました。管理者に連絡してください");
        Application.login("http://server/startup.crs");
        return false;
    }
}
:

onExceptionハンドラは、アプリケーション固有のエラー報告手段を提供するために用意された機能で、通常はユーザに対してエラーを報告して終了します。

onExceptionハンドラに制御が渡った時点で、実行途中のコールスタックは全て解放されているので、 エラーを起こしたスクリプトの処理を継続させることはできません。

また、onExceptionの処理中に別の例外が発生した場合、Biz/Browserに内蔵されているエラーハンドラが実行されます。


onException関数がtrueを返した場合、CRSインタプリタはセッションを維持したまま処理を継続します。

true以外を返した場合、CRSインタプリタはセッションをリセットして停止します。

処理の継続が可能な例外は、個々の処理の中でtry ...  catchにより捕捉してonExceptionに制御が渡らないようにしてください。


onExceptionが実行される局面では、例外の発生した位置や内容が特定できませんので、画面が正常に表示されていなかったり、 オブジェクトの生成が途中で停止しているなど意図しない状態に陥っている可能性があります。

ooExceptionはエラー報告を行った後、処理を停止するかApplication.login()メソッドによりセッションをリセットして アプリケーションを再起動することを推奨します。