LoginSignup
3
1

More than 3 years have passed since last update.

Ruby 例外処理について

Last updated at Posted at 2020-08-07

例外処理とは

例外処理を行うことで、エラー原因やエラー箇所の特定や、発生したエラーに対する適切な処理を行うことができます。

本記事では、以下について紹介していきます。

  • rescue
  • ensure
  • 例外処理の戻り値
  • return
  • rescue修飾子
  • 特殊変数 $! $@
  • メソッド全体に例外処理を設ける(begin/endの省略)
  • raise
  • カスタム例外を作成

rescue

以下のようにbeginの下に、通常実行したいプログラムを記述します。
そのプログラムの実行中に例外が発生した場合に、呼び出したいコードをrescueの下に記述します。

begin
  p "実行するコード"
rescue
  p "例外が発生した場合に実行されるコード"
end

結果

"実行するコード"

else

rescueに、elseを付け加えることによって
例外が発生しなかった場合に呼び出したいコードを追加できます。

begin
  p "実行するコード"
rescue
  p "例外が発生した場合に実行されるコード"
else
  p "例外が発生しなかった場合に実行されるコード"
end

結果

"実行するコード"
"例外が発生しなかった場合に実行されるコード"

rescueの使用例

例外が発生したら、「エラーが発生しました!」というメッセージを表示するブログラムを作成します。

文字列を""(ダブルクォーテーション)で囲っていないので例外となり、rescueの下にあるコードが実行されます。

begin
  p 文字列
rescue
  p "例外が発生しました"
end

結果

"例外が発生しました"

ensure

例外処理にensureを使用することで、例外の有無に関わらず実行される処理を記述することができます。

begin
  p "実行するコード"
rescue
  p "例外が発生した場合に実行されるコード"
else
  p "例外が発生しなかった場合に実行されるコード"
ensure
  p "例外の有無にかかわらず 最後に実行されるコード"
end

結果

"実行するコード"
"例外が発生しなかった場合に実行されるコード"
"例外の有無にかかわらず 最後に実行されるコード"

使用用途としては、何らかの処理を行っている時にエラーが発生した場合でも、確実に実行したい処理がある場合に使います。
(例)ファイルを開いて作業するプログラムの場合、「実行中の例外発生に関わらず、最後に必ずファイルを閉じておく」といったことができます。

例外処理の戻り値

  • 例外発生せず正常に処理が終了した場合、beginの最後の式が戻り値となります。
  • 例外が発生した場合、rescueの最後の式が戻り値となります。

(例) 処理が正常に終了した場合

class Return
  def test(n)
    begin
      1 / n
      "Begin"
    ensure
      "Ensure"
    end
  end
end

obj = Return.new
p obj.test(1)
"Begin"

(例) 例外処理が発生した場合

class Return
  def test(n)
    begin
      1 / n
      "Begin"
    rescue
      'Rescue'
    ensure
      "Ensure"
    end
  end
end

obj = Return.new
p obj.test(0)
"Rescue"

return

ensure内にreturn文を記述すると、

  • 例外発生が取り消され、正常終了してしまう
  • 例外発生の有無に関わらず、ensureの値がメソッドの戻り値となってしまう

このことから、本来期待した処理が実行されません。

例外発生が取り消され、正常終了してしまう

本来は下記のようにrescueをなくし、ensureのみ記述した場合は、例外処理が発生すると異常終了となります。

class Return
  def test(n)
    begin
      1 / n
      "Begin"
    ensure
      "Ensure"
    end
  end
end

obj = Return.new
p obj.test(1)
p obj.test(0)

結果

(ZeroDivisionError)

しかし、ensure内にreturn文を記述すると、下記のように正常終了してしまいます。

class Return
  def test(n)
    begin
      1 / n
      "Begin"
    ensure
      "Ensure"
      return "return ensure"
    end
  end
end

obj = Return.new
p obj.test(1)
p obj.test(0)

結果

"return ensure"
"return ensure"

例外発生の有無に関わらず、ensureの値がメソッドの戻り値となってしまう

class Return
  def test(n)
    begin
      1 / n
      "Begin"
    rescue
      'Rescue'
    ensure
      "Ensure"
      return "return ensure"
    end
  end
end

obj = Return.new
p obj.test(1) # 本来は"Begin"が返ってくる
p obj.test(0) # 本来は"Rescue"が返ってくる

結果

"return ensure"
"return ensure"

rescue修飾子

rescueは修飾子のように使うこともできます。
以下のように、普通に記述すると5行は書かないといけない処理がrescue修飾子を使うと1行でスッキリと記述することができます。

class Return
  def test
    begin
      文字列
    rescue
      "error!!!"
    end
  end
end

obj = Return.new
p obj.test

rescue修飾子を使用すると1行で書けます!

class Return
  def test
    文字列 rescue "error!!!"
  end
end

obj = Return.new
p obj.test

結果

"error!!!"

特殊変数

特殊変数とは、rubyに用意された特別な意味を持つ変数のことです。
rescueで例外オブジェクトを代入する変数は、指定の有無に関わらず値が代入されます。

特殊変数$!

例外が起こった時にその例外オブジェクト(Exception)が代入されます。もしも複数の例外があった場合は一番最後の例外オブジェクトが代入されることになります。例外が発生しなかった場合にアクセスすると nil が得られます。

特殊変数$@

例外が起こったバックトレースを配列にして代入してくれます。バックトレースとは、例外を発生させたプログラム全体の流れを追って、原因となったコードの情報を示すものです。

引用参考文献

使用例

コンソール(irbやpry)で例外が発生しても、バックトレースが表示されないことにより、原因がわからない場合があります。
コンソールで例外時のバックトレースを表示するには、特殊変数$@を使用します。

irb(main):002:0> puts $@

メソッド全体に例外処理を設ける(begin/endの省略)

メソッド全体に例外処理を設ける場合は、begin/endを省略することができます。

begin/endを記述した例


def hoge
  begin
    p 1/0
  rescue
    p "エラー!!!"
  end
end

begin/endを省略した例

def hoge
  p 1/0
rescue
  p "エラー!!!"
end

raise

raiseメソッドは意図的に例外を引き起こすためのメソッドです。

下記のように記述すると、raiseメソッドにより例外が引き起こされ、rescueメソッドが実行され、「エラー!!!」と出力されます。

begin
  raise
  rescue
    p "エラー!!!"
end
"エラー!!!"

このメソッドはrescue内でも使用することができます。
使用用途としては、例外発生時にプログラムを異常終了させることに加えて、例外情報をログに記録したり、メール送信したい場合に使うことができます。

class Return
  def test(n)
    begin
      1 / n
      "Begin"
    rescue
      p "エラー!!!(log)"
      raise
    end
  end
end

obj = Return.new
obj.test(0)
"エラー!!!(log)"
Traceback (most recent call last):
        2: from ruby.rb:14:in `<main>'
        1: from ruby.rb:4:in `test'
ruby.rb:4:in `/': divided by 0 (ZeroDivisionError)

カスタム例外を作成

例外クラスはRubyのクラスと同様です。
StandardErrorを継承する独自の例外クラスを作成します。

(例)

class Error < StandardError
end

全てのrubyの例外オブジェクトはmessage属性を持っています。
以下のように独自の例外にデフォルトのメッセージを定義してみます。

class Error < StandardError
  def initialize(msg="Error Message")
  super
  end
end

raise Error #=> Error Message

独自のデータを例外に付け加えることができます。


class Error < StandardError
  attr_reader :attr

  def initialize(msg="default Error message", attr="value")
    @attr = attr
    super(msg)
  end
end

begin
  raise Error.new("Error message", "value")
rescue => e
  puts e.attr #=> value
end

これで、独自の例外を作成できました。

参考記事
https://qiita.com/k-penguin-sato/items/3d8ce4e71520da2d68c4

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1