RubyのExceptionとStandardErrorの違いとは?rescueの正しい使い方を徹底解説
「Rubyで決してExceptionをrescueしてはいけない!」
こんな警告を耳にしたことがあるかもしれません。確かに良いアドバイスなのですが、詳しい人でなければ意味が分かりにくいものです。この記事では、この一文の意味を丁寧に解きほぐしていきます。
Rubyでは例外を次のようにrescueできることは、ご存知の方も多いでしょう。
begin
do_something()
rescue => e
puts e # eはエラー情報を含む例外オブジェクト
end
さらに、例外クラス名を指定すれば、特定のエラーだけを捕捉することもできます。
begin
do_something()
rescue ActiveRecord::RecordNotFound => e
puts e # RecordNotFound、およびそのサブクラスの例外のみを捕捉
end
Rubyにおけるあらゆる例外は、実は単なるクラスです。上の例でいうActiveRecord::RecordNotFoundは、一定の規約に従ったクラス名にすぎません。
ここが重要なポイントです。RecordNotFoundをrescueすると、そのクラスを継承している例外もすべて一緒に捕捉されてしまいます。
なぜExceptionをrescueしてはいけないのか
Exceptionをrescueすることの問題点は、Exceptionを継承するすべての例外を捕捉してしまうことにあります。そう……全部です!
これが問題になるのは、Rubyが内部で使用している例外が存在するからです。それらはアプリケーションとは無関係のものであり、うっかり握りつぶしてしまうと深刻な事態を引き起こします。
代表的な例をいくつか挙げます。
SignalException::Interrupt - これをrescueしてしまうと、Ctrl+Cでプロセスを中断できなくなります。
ScriptError::SyntaxError - 構文エラーを握りつぶすと、
puts("Forgot something)のような書き間違いがサイレントに失敗し、気づくのが遅れます。NoMemoryError - メモリを使い果たした後もプログラムが動き続けたらどうなるのか……知らなくて済むなら、それに越したことはありません。
begin
do_something()
rescue Exception => e
# これはNG。すべての例外が握りつぶされ、何ひとつ外に漏れません。
end
おそらくあなたは、こうしたシステムレベルの例外を捕捉したいわけではないはずです。本当に捕まえたいのは、自分のコードが引き起こしたアプリケーションレベルのエラーだけでしょう。
幸い、それを実現する方法はとてもシンプルです。
代わりにStandardErrorをrescueしよう
私たちが普段気にかけるべき例外は、すべてStandardErrorを継承しています。おなじみの仲間たちです。
NoMethodError - 存在しないメソッドを呼び出そうとしたときに発生
TypeError -
1 + ""のような型不一致の処理で発生RuntimeError - 言わずと知れた定番のRuntimeError
こうしたエラーを捕捉するには、StandardErrorをrescueします。次のように明示的に書くこともできます。
begin
do_something()
rescue StandardError => e
# アプリ自身の例外だけが捕捉されます。SyntaxErrorなどは素通りします。
end
しかし実は、Rubyはもっと便利な仕組みを用意してくれています。
例外クラスを一切指定しなかった場合、Rubyは自動的にStandardErrorを指定したものとみなします。つまり、次のコードは上のコードと完全に同じ意味になります。
begin
do_something()
rescue => e
# StandardErrorをrescueするのと同じ
end
独自の例外はStandardErrorを継承すべき
では、自分でカスタム例外クラスを作る場合はどうすればよいのでしょうか?
答えは明快です。必ずStandardErrorを継承し、決してExceptionを直接継承してはいけません。Exceptionを継承してしまうと、rescueの期待される挙動が壊れてしまいます。「アプリケーションレベルのエラーはすべて捕捉しているはず」と信じていたのに、あなたの作った例外だけはrescue文を素通りしてしまうのです。
class SomethingBad < StandardError
end
raise SomethingBad
Rubyの例外ツリー(継承階層)
Rubyの例外はクラス階層として実装されているため、全体像を一度目にしておくと理解がぐっと深まります。以下は、Ruby標準ライブラリに含まれる例外クラスの一覧です。Railsなどのサードパーティgemはさらに多くの例外クラスを追加しますが、それらもすべてこの一覧のどこかのクラスを継承しています。
Exception
NoMemoryError
ScriptError
LoadError
NotImplementedError
SyntaxError
SignalException
Interrupt
StandardError
ArgumentError
IOError
EOFError
IndexError
LocalJumpError
NameError
NoMethodError
RangeError
FloatDomainError
RegexpError
RuntimeError
SecurityError
SystemCallError
SystemStackError
ThreadError
TypeError
ZeroDivisionError
SystemExit
fatal
-
OneDriveとOneDrive for Businessの違いとは?使い分けのポイントを徹底解説
Microsoftのクラウドストレージサービス「OneDrive」を使えば、どこにいても自分のファイルにアクセスできます。しかし、実はMicrosoftは名前がよく似た2種類のOneDriveを提供しています。「OneDrive」と「OneDrive for Business」のどちらを使うべきかは、クラウドに何を保存するのか、そしてどうやってアクセスする必要があるのかによって変わってきます。 OneDrive(個人向け)の特徴 「OneDrive」は、個人ユーザー向けに設計されたMicrosoftのクラウドサービスです。個人のOutlookアカウントに含まれており、Windows 10では自
-
Windows 10 HomeとProの違いを徹底解説!自分に合ったエディションの選び方
新しいPCの購入を検討している場合でも、Windowsを単体で購入する場合でも、Windows 10 HomeとProの違いをあらかじめ把握しておくことが大切です。製品ページなどに特に表記がない場合は、そのデバイスにはWindows 10 Homeが搭載されていると考えてよいでしょう。 そもそも「Home」という名称はやや分かりにくく、実態としては「Windows 10 スタンダード」と呼ぶ方がぴったりです。価格1,000ポンド(約15万円)未満のWindowsデバイスの大半に搭載されており、OSのコア機能がすべて含まれています。 一方のProは、プロフェッショナル、パワーユーザー、ビジネ