※最後に問題があるのでぜひチャレンジしてみてください!
背景
- 最近Rubyの基礎的な部分を学び直している
- 実装で例外処理について考える事が多かった
例外とは
- 例外(Exception)とは文字どおり、プログラムの実行中(場合によっては実行前)に発生した「例外的な問題」のこと。」
- 例えば以下のようなケースのこと
- 0 で割り算してしまった
- 存在しないメソッドを呼び出した
- nil に対してメソッドを呼んだ
- 例えば以下のようなケースのこと
- とくに手を打たなければ、例外が発生した時点でプログラムの実行は終了する
puts 'Start'
1 / 0
puts 'End'
# この場合、End は表示されない
# 途中でエラーが起きて処理が止まる為
- 例外を適切にハンドリングすることによりプログラムを続行させるのか、終了させるのか制御することが重要になってくる
例外を捕捉して処理を実行する
beginは書かなくても動くが、例外が発生しうる処理。を明示的にする為に記載することが一般的となっている
puts 'Start.'
begin
# 例外が起きうる処理
1 / 0
rescue
# 例外が発生した場合の処理
puts '例外が発生したが、このまま続行する'
end
puts 'End.'
#=> Start.
例外が発生したが、このまま続行する
End.
- ポイント
- 1 / 0 で例外は発生している
- しかし rescue で例外が補足されるため、プログラムは止まらない
- 「エラーが起きても続ける」選択ができる
クラスを指定して捕捉する例外を限定する
puts 'Start.'
begin
1 / 0
rescue ZeroDivisionError
puts '例外が発生したが、このまま続行する'
end
puts 'End.'
#=> Start.
例外が発生したが、このまま続行する
End.
- ポイント
- クラスを指定するとその例外だけを捕まえる
- 補足
- 例外クラス未指定の場合はデフォルトでStandardErrorが指定される
例外クラスの継承関係
例外クラスは以下のような**継承(親子関係)**を持っている

- ポイント
- 親クラスは、子クラスもまとめて捕まえる
- 例)NameError は NoMethodError の親クラス
よくない例外処理
begin
# NoMethodErrorを発生させる
'abc'.hogehoge
rescue NameError
# NoMethodErrorはここで捕捉される
puts 'NameErrorです'
rescue NoMethodError
# このrescue節は永遠に実行されない
puts 'NoMethodErrorです'
end
#=> NameErrorです
例題
Q. 以下のコードがあります。
class SomeError < StandardError; end
class SomeOtherError < SomeError; end
def meth1
raise SomeOtherError.new("error")
end
begin
meth1
rescue SomeError
print "SomeError"
rescue SomeOtherError
print "SomeOtherError"
end
実行結果として正しいものを選択してください。(1つ選択)
- (a) A syntax error
- (b) SomeError
- (c) SomeErrorSomeOtherError
- (d) SomeOtherError
解答
(b) SomeError
- 継承関係として、SomeOtherError < SomeError < StandardError となっている
- SomeOtherErrorはSomeErrorのサブクラスなので、rescue SomeError節が該当して実行される。
- 現実のアプリケーションでは、一般的なエラーよりも特定的なエラーから順にrescueするのがよい習慣
- (例えば、rescue StandardErrorは最後に記述する)。
最後に(私が考えたこと)
- 例外の継承関係を理解しないと
- 不適切なエラーハンドリングを行ってしまう可能性
- 無闇に一般的な例外クラス(
StandardError)をresuceしていると、バグを隠蔽してしまう危険性がある- 発生し得る例外が予測できる場合は
- より特定の例外クラス(
ZeroDivisionError)をresuce - 条件分岐により早期リターン(
return if hogehoge.valid?)も良い
- より特定の例外クラス(
- 発生し得る例外が予測できる場合は