Rubyの例外処理復習

この記事について

Rubyの例外処理について「プロを目指す人のためのRuby入門」で復習してたので重要だと思ったところをまとめます。

rescue節は例外クラスを指定しなかった場合StandardErrorを継承していない例外クラスを捕捉しない

具体的には、NoMemoryError, ScriptError, SecurityErrorなど

Class: Exception (Ruby 2.6.1)

なお、例外クラスを指定した場合はそのクラス自身とそのサブクラスを捕捉する

begin
  1 / 0
rescue StandardError => e  
  puts "#{e.class}"
end  

#=> ZeroDivisionError
# ZeroDivisionErrorはStandardErrorのサブクラス

例外発生時にもう一度処理をやり直す

rescue節でretry文を実行するとbegin節の最初から処理をやり直すことができる

counter = 0

begin
  '処理を開始します'
  1 / 0
rescue
  counter += 1
  if counter <= 3
    puts "retryします: #{counter}回目"
    retry
  else
    puts 'retry失敗しました'
  end
end

# 実行結果
$ ruby test.rb 
retryします: 1回目
retryします: 2回目
retryします: 3回目
retry失敗しました

意図的に例外を発生させる

raiseメソッドを使うと意図的に例外を投げることができる

def greeting(country)
  case country
  when :japan
    'こんにちは'
  when :us
    `hello`
  else
    raise "無効な国名です。#{country}"
  end
end

greeting(:japan) #=> こんにちは
greeting(:us)    #=> hello
greeting(:korea) #=> RuntimeError: 無効な国名です。korea

この際、投げる例外のクラスを指定できるが、独自の例外を作ることもできる

class NoCountryError < StandardError; end

def greeting(country)
  # 省略

  raise NoCountryError, "無効な国名です。#{country}"

  # 省略
end

greeting(:korea) #=> NoCountryError: 無効な国名です。korea

rescueは修飾子としても使うことができる

1 / 0 rescue 0 #=> 0

そのほか覚えておきたいこと

  • 例外処理のベストプラクティス 機能としては用意されていても、それを使うべき時と使うべきでない時がある

    • Railsのようなフレームワークでは、例外発生時の共通処理が最初から組み込まれている(具体的には、エラーメッセージやバックトレースをログに書き込み、ユーザに対してはエラーの発生を画面上で通知してくれる)ので、フレームワークのレールに乗った方が良いことが多い
  • 例外処理より条件分岐を使う

    • 安易に例外処理を使うと可読性が落ち、意図しない動作が起こる可能性が高くなりやすい

まとめ

忘れていたことも多く、良い復習になりました。 仕事ではRailsを使っているため、うまくレールに乗って不要なところで例外処理を書かなくていいように心がけようと思います。

参考書籍

https://www.amazon.co.jp/%E3%83%97%E3%83%AD%E3%82%92%E7%9B%AE%E6%8C%87%E3%81%99%E4%BA%BA%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AERuby%E5%85%A5%E9%96%80-%E8%A8%80%E8%AA%9E%E4%BB%95%E6%A7%98%E3%81%8B%E3%82%89%E3%83%86%E3%82%B9%E3%83%88%E9%A7%86%E5%8B%95%E9%96%8B%E7%99%BA%E3%83%BB%E3%83%87%E3%83%90%E3%83%83%E3%82%B0%E6%8A%80%E6%B3%95%E3%81%BE%E3%81%A7-Software-Design-plus%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA/dp/4774193976/ref=tmm_other_meta_binding_swatch_0?_encoding=UTF8&qid=&sr=