例外処理について学ぶマン

はいどーもニートですこんばんは。
みなさん例外処理してますか?
出口は一つにしちゃってますか?
僕はしてません。
これから意識していこうと思います。
というわけで、例外処理のお勉強もといおさらい記事です。

例外処理ってなんやねん

プログラムを実行していると、エラーがよく起きます。
この前書いたエラー情報の見方なんかでもわざとエラーを起こしてますね。
このエラーを処理する方法の一つを例外処理と呼びます。
JavaScriptは例外を処理するための命令を持っていますが(try-catch-finally)、別に特別な命令を使わなくてもエラーを処理することはできます。
例えばC言語なんかでは、戻り値によってエラーが発生したかどうかを確認するようです。
ですがなんやかんやで不便なので(詳細はググってください)例外処理のための命令が生まれました。
その一つがtry-catch-finally命令です。

どうやって使うねん

歴史的なお話は横に置いておき、さっそく例外を処理してみましょう。
とりあえずはコードをペタリ。

var throwError = function(){
throw new Error('エラーだよ!');
console.log('これは実行されない');
};

var createError = function(){
try{
throwError();
}catch(e){
console.log('伝搬させないでござるよ');
}
};

var test = function(){
try{
createError();
}catch(e){
console.log(e.message);
}
}();

最初のthrowErrorは例外を投げる関数(変数に代入している)です。
例外が投げられると、そこで処理は中断されます(returnみたいな感じ)。
したがって次の行のconsole.log('これは実行されない');は実行されません。

次のcreateError関数は先ほど作ったthrowError関数を実行しています。
その際、try-catchで囲っています。

最後のtest関数は即時関数となっており、createError関数を呼び出す処理をおこなっています。
また、見てわかるようにtry-catchで囲っています。

と、コードを見ていただければわかるように、try-catchの使い方はシンプルです。
これ自体は特に問題ないと思うのですが、投げられた例外が伝搬することは意識しておく方がよいでしょう。

例外は伝搬する

上のコードを実行してみください。
「伝搬させないでござるよ」とコンソール画面に表示されると思います。
この結果から、try句で捕まえた例外は、それより外に向かって伝搬しない(catch句で潰される)ことがわかると思います。
ではcreateError関数のtry-catch命令を除けた場合はどうでしょうか?
この場合、createError関数は例外をキャッチしないため、createError関数の呼び出し元であるtest関数に例外が伝搬します。
つまりtest関数のtry-catch命令で例外がキャッチされます。

伝搬のさせかた

「例外が発生したことはその関数内で知りたいんだけど、呼び出し元に例外を伝搬させたい場合はどうすればいいのよおおおお」というお嬢さんもいるかなと思います。
簡単です。例外を再スローさせればいいのです。
お嬢さんのためにサンプルコードも添付しておきます(ニートはいつだって紳士オブ紳士。結婚相手募集中です)。

var throwError = function(){
throw new Error('エラーだよ!');
console.log('これは実行されない');
};

var createError = function(){
try{
throwError();
}catch(e){
console.log('伝搬させちゃうでござるよ');
throw e;//new Error('君に届け俺のエラー!');
}
};

var test = function(){
try{
createError();
}catch(e){
console.log('おやおや');
console.log(e.message);
}
}();

throw e;の部分が例外の再スローです。
C#だと例外を再スローさせる場合、単にthrowとだけ書くのが作法のようですが、JavaScriptの場合は構文エラーが出るのでcatchしたエラーオブジェクトをぶん投げましょう。
ちなみにですが、コメントで「君に届け俺のエラー!」と書いてある方法だと、また別の新しいエラーを作成し、伝搬させることになります。
それが意図した動作なら問題ないですが、単にエラー情報を伝搬させたいだけならcatchしたエラーオブジェクトをそのまま投げる方がいいのかなあと思いました(この辺は僕もまだ曖昧です)。

終わりに

try-catch-finally命令は全体として重いらしいです(今回finallyは使ってませんが、出口を一つにするためにはこのfinallyを使います)。
特にループの中でぶん回すとアババババなことになるらしいので、エラーの処理をおこないたい場合でも、なるべくループの中では別の方法を模索した方がいいかもしれませんね(戻り値でエラーを判定するのも手かも?)。
と偉そうに書いていますが、実は僕も例外処理を実践でうまく使えたことはありません。
便利なんだろうなとは思っていますので、ぼちぼち使っていきたいと思います。

ほな、そんな感じで。

フォローする