プログラムにおいて処理を続行することが不可能なエラーが発生した場合には、例外処理を行います。
例外処理は、本来実行したい処理とは異なる部分ですが、全く記述しなかったり、不適切に記述すると、エラー発生時にシステムが停止してしまったり、必要な情報を残すことができなかったりするなどの重大な事態を招いてしまう恐れがあります。
ですから、実際の開発現場でプログラミングをするには、必須の処理となります。
本ブログではこれまでに、例外処理の方法を、JavaScript、Python、Java、Ruby、Goの5つの言語について書きました。
本記事では、5つの言語の例外処理でどんな違いや注意点があるのかを解説します。
それぞれの言語で例外に対する思想の違いなども見えてきて、面白い結果になっていますので、ぜひご覧いただきたいと思います。
各言語の詳細は、最後に関連記事としてまとめておきますので、気になる方はご覧ください。
プログラミング言語の例外処理まとめ
各言語で、主に以下の内容についてまとめてきましたので、これらの内容について5つの言語で比較してみます。
- 例外の捕捉方法
- 例外の投げ方
- 例外が発生しなかった場合のみ処理を実行する方法
- 例外が発生しても、しなくても必ず処理を実行する方法
- 例外情報の作成方法
- 例外情報の取得・出力方法
例外の捕捉方法
言語 | 方法 | 注意点など |
---|---|---|
JavaScript
|
try…catch文
|
catch文では基本的にどんな型の例外でも捕捉する。
|
Python
|
try…except文
|
except文で捕捉したい例外情報を指定できる(指定することが基本的に推奨されている)。 |
Java
|
try…catch文
|
catch文で捕捉したい例外情報を指定する必要がある。
|
Ruby
|
begin…rescue…end文
|
rescue文で捕捉したい例外情報を指定できる。 |
Go
|
例外処理機構がない
(戻り値でエラー情報を返す)
|
Go以外の言語では、共通して例外が発生する可能性がある処理をtryやbeginでブロック化し、発生した例外をcatch、except、rescueで捕捉するというのが基本的な文法になります。
Goについては、そもそも言語仕様で例外処理を扱う機能を提供していません。(理由については、記事の内容をご参照ください)
例外の投げ方
言語 | 方法 | 注意点など |
---|---|---|
JavaScript
|
throw文
|
|
Python
|
raise文
|
|
Java
|
throw文
|
投げる例外クラスをメソッド定義のthrowsに指定する必要がある(チェック例外の場合)。
|
Ruby
|
raise文
|
|
Go
|
例外情報を投げることはできないが、エラー情報をfmtパッケージのErrorfで作成する。
|
プログラマー自身が例外情報を作成するケースでは、それぞれ言語において専用の文法が用意されています。
Java言語においては、静的型付けということもあり、投げるクラスを明示的にメソッド定義に記述する必要がありますが、例外を投げることで到達不能なコードがあると、コンパイル時に教えてくれるといった恩恵があったりします。
例外が発生しなかった場合のみ処理を実行する方法
言語 | 方法 | 注意点など |
---|---|---|
JavaScript
|
なし
|
|
Python
|
else文
|
|
Java
|
なし
|
|
Ruby
|
else文
|
|
Go
|
なし
(戻り値で受け取ったエラー情報がnilの場合の処理を実装することは可能)
|
RubyとPythonには、例外の捕捉方法に、else文を追加することができます。
JavaScriptとJavaには言語仕様としては用意されていませんが、finallyで例外が発生したかをチェックするなど、別の方法でも対応は可能かと思います。
例外が発生しても、しなくても必ず処理を実行する方法
言語 | 方法 | 注意点など |
---|---|---|
JavaScript
|
finally文 | |
Python
|
finally文 | |
Java
|
finally文
|
|
Ruby
|
ensure文
|
|
Go
|
なし
|
リソースの解放処理など、例外が発生しても、しなくても必ず必要となる処理をGo言語以外では用意しています。
変数を扱う場合にはスコープに注意して取り扱います。
例外情報の作成方法
言語 | 方法 | 注意点など |
---|---|---|
JavaScript
|
throw文に任意の型の情報を指定することが可能。
|
独自の例外情報を利用する場合は、基本的にErrorオブジェクトを継承する。
|
Python
|
raise文に任意の型の情報を指定することが可能。 |
独自の例外情報を利用する場合は、基本的にExceptionオブジェクトを継承する。
|
Java
|
throw文に任意の型の情報を指定することが可能。
|
独自の例外情報を利用する場合は、基本的にExceptionクラスを継承する。
チェック例外と非チェック例外がある。
|
Ruby
|
raise文に任意の型の情報を指定することが可能。 |
独自の例外情報を利用する場合は、基本的にStandardクラスを継承する。
|
Go
|
fmt.Errorfで作成する。
|
例外情報は、基本的にどの言語でも投げたい例外クラスにエラーメッセージを設定して作成します。
どの言語に置いても独自の型の情報を投げることはできますが、各言語が用意しているクラスを利用したり、それらを継承したクラスとすることが多いです。
例外情報の取得・出力方法
言語 | 方法 | 注意点など |
---|---|---|
JavaScript
|
スタックトレースはErrorオブジェクトのstackプロパティから取得する。
|
|
Python
|
スタックトレースはtracebackモジュールを使い、format_excで取得する。
|
|
Java
|
スタックトレースはgetStackTraceで取得、またはprintStackTraceで出力する。
|
|
Ruby
|
バックトレースはExceptionクラスのbacktraceで取得する。
|
|
Go
|
スタックトレースを直接取得する方法はないが、例外情報をラップしていくことでスタックトレースのような情報を構築することは可能。
|
例外発生時の情報となるスタックトレース、バックトレース情報は、基本的に各言語のエラーオブジェクトから取得することができます。
その他
例外処理に関するその他として、Rubyには以下の機能もあります。
- retry文:begin内の処理を再実行する
- rescue修飾子:メソッド呼出しなどの式の後に、beginなしで例外処理を行うことができる。
rubyには開発者が独自に実装しなくても良いように様々な機能が提供されています。使い方が気になる方は、記事をご参照ください。
例外処理は運用時の要
どんなに素晴らしいプログラムでも、OSやハードウェア上で動いているからには、いつかはエラーが発生します。
運用時に発生したエラーを、後からでも調査可能な状態にしておくためには、例外処理が不可欠です。
原因調査のために、分かりやすいエラー情報をいかに残しておくかが、プログラマーとしての腕の見せ所になります。
プログラミングしている時は、例外処理は優先度が低かったり、おざなりにされがちだったりしますが、とても重要な処理であることを認識してもらえると嬉しいです。
僕自身も自分が作ったプログラムを、自分で長年運用して、例外処理がとても重要であることを学びました。
それからは、正常系のプログラムを書くよりも、例外処理を適切に書ける人が、良いプログラマーであると感じています。
今回は、プログラミング言語の例外処理についてまとめてみました。
各言語の詳細は、下記の記事にまとめていますので、気になる点がある方はご覧ください。
参考になれば幸いです。
コメント