例外処理とは
例外処理を行うことで、エラー原因やエラー箇所の特定や、発生したエラーに対する適切な処理を行うことができます。
本記事では、以下について紹介していきます。
- 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 が得られます。
特殊変数$@
例外が起こったバックトレースを配列にして代入してくれます。バックトレースとは、例外を発生させたプログラム全体の流れを追って、原因となったコードの情報を示すものです。
[引用参考文献]
(https://qiita.com/tsubasakat/items/6825bcefcad26da3471b)
使用例
コンソール(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