Rubyの例外処理

例外とは通常の処理を行なう上で何か問題があるとき(エラー)に対処するためのものです。何も指定がないときエラーがあるとプログラムは終了してしまいます。しかし、例外処理を使用することによってエラーが発生した場合でも、プログラムを停止させることなく条件に応じた処理を行うことができます。

例外処理の基本

例外処理を行う場合は、例外処理を行いたい部分をブロックで囲みます。そして、その囲まれたブロックに対して例外処理を記述していきます。

例外を処理する:rescue

エラーが発生した場合の処理を rescue ブロックに書きます。エラーが発生しなかったときに限って行う処理を else ブロックに書きます。エラーが発生したかどうかにかかわらず処理をしたいときは ensure ブロックを使います。

以下は begin ~ end のブロックで例外を捕捉し処理する例です。

begin
  #エラーが発生する可能性のある処理
rescue
  #エラーが発生した場合の処理
else
  #エラーが発生しない場合の処理
ensure
  #エラー発生の有無にかかわらず行う処理
end

以下は例外処理のサンプルプログラムです。

# sample.rb
def div(x, y)
  begin
    puts "処理を開始します"
    x / y
  rescue
    puts "エラーが発生しました"
  else
    puts "エラーは発生していません"
  ensure
    puts "エラーの有無にかかわらずメッセージを出しています"
  end
end

puts "> div(7, 3)"
div(7, 3)

puts "> div(9, 0)"
div(9, 0)

実行結果

$ ruby sample.rb
> div(7, 3)
処理を開始します
エラーは発生していません
エラーの有無にかかわらずメッセージを出しています
> div(9, 0)
処理を開始します
エラーが発生しました
エラーの有無にかかわらずメッセージを出しています

結果の前半、後半部はそれぞれ div(7, 3)、div(9, 0) に対応しています。

div(7, 3) が実行されると、begin から処理がはじまり、"処理を開始します" のメッセージを出した後、x / y が実行されますが、特にエラーは発生しないので else ブロックが実行され、"エラーは発生していません" と表示されます。rescue ブロックは実行されません。最後に ensure ブロックが実行されて "エラーの有無に関わらずメッセージを出しています" が表示されます。

div(9, 0) が実行されると、ゼロで割ることはできないので x / y のところでエラーが発生し、rescue ブロックが実行され "エラーが発生しました" と表示されます。

また、上の例はメソッドのブロッグで囲まれているので、以下のように begin, end を省略することもできます。

def div(x, y)
  puts "処理を開始します"
  x / y
rescue
  puts "エラーが発生しました"
else
  puts "エラーは発生していません"
ensure
  puts "エラーの有無にかかわらずメッセージを出しています"
end

同様にクラス・モジュールでも begin, end を省略することができます。

例外を発生させる:raise

raise を使うことで処理中に例外を発生させ、通常の処理を中断して処理の流れを例外処理に渡すことができます。

# sample2.rb
def input(x)
  puts x
  raise ArgumentError, '文字列でないものが入力されました' unless x.is_a? String
end

input("a")

input(11)

実行結果

$ ruby sample2.rb
a
11
sample2.rb:3:in `input': 文字列でないものが入力されました (ArgumentError)
	from sample2.rb:8:in `<main>

unless x.is_a? String で x が文字列かどうかを判定します。xが文字列でないときは例外を発生させ "文字列でないものが入力されました"というメッセージを出力しています。

捕捉した例外の情報を表示する

発生した例外がどのようなものかを表示するには rescue 節で => e を指定することで、例外オブジェクトを取得し例外の情報を表示することができます。

begin
  9 / 0
rescue => e
  puts e.class      # ZeroDivisionError
  puts e.message    # divided by 0
  puts e.backtrace  # [sample.rb:4:in `/', sample.rb:4:in `div', sample.rb:12:in `<main>' end]
end

上の例のように例外クラス Exception にはいくつかのメソッドが用意されており、class, message, backtraceなどのメソッドを利用することで例外の情報を表示することができます。

特定の例外のみ捕捉する

rescue 節に例外のクラスを指定することによって、特定の例外のみを捕捉することができます。

begin
  # 何らかの処理
rescue ZeroDivisionError => e
  # 例外処理
rescue ArgumentError, NameError => e
  # 例外処理
end

resuce 節に何も指定していない場合は、StandardError とそのサブクラスの例外処理を捕捉します。また、カンマで複数の例外を指定することによって、複数の例外を捕捉することができます。