例外処理を用いることで、エラーが発生したときに行う処理を記述しておくことができます。
以下から Ruby の例外処理で用いる「begin・rescue・raise」の使い方を解説していきます。
そもそも例外処理とは何か? という解説はこちら。
例外処理の基本
rescue の使い方
以下のように begin
の下に、通常 実行したいプログラムを書きます。そのプログラムの実行中に例外が発生したときだけ呼び出したいコードを rescue
の下に書きます。
begin
実行するコード
rescue
例外が発生したときだけ実行されるコード
end
また、else
を付け加えることで、以下のように例外が発生しなかったときだけ呼び出したいコードを追加することができます。
begin
実行するコード
rescue
例外が発生したときだけ実行されるコード
else
例外が発生しなかったときだけ実行されるコード
end
ensure の使い方
以下のように ensure
を付け加えると、例外の有無に関わらず 最後に実行したいプログラムを追加できます。
begin
実行するコード
rescue
例外が発生したときだけ実行されるコード
else
例外が発生しなかったときだけ実行されるコード
ensure
例外の有無にかかわらず 最後に実行されるコード
end
raise の使い方
例外を意図的に起こしたい場合は、プログラム中で以下のように記述します。
raise
例外の種類を指定したい場合は、以下のように後ろにエラーの種類を記述します。
raise エラーの種類
例外処理を使ったプログラム例
実際にプログラムを書いて動作を確認してみましょう。
例外が発生したときだけ実行するコードを追加する(rescue の使用例)
以下は例外が発生したら「例外が発生しました」というメッセージを表示するプログラム。
数値を0で割る計算(1/0
)はできないので例外となり、rescue
の下にあるコードが実行されます。
begin
p 1/0
rescue
p "例外が発生しました"
end
"例外が発生しました"
例外が発生したときにエラー情報を取得する
rescue
のあとに => 変数名
をつけることで、指定した変数名でエラー情報を取得することができます。
以下は「e」という変数名でエラー情報を取得する例。
begin
p 1/0
rescue => e
p e
p e.class # 例外の種類
p e.message # 例外のメッセージ
p e.backtrace # 例外が発生した位置情報
end
#<ZeroDivisionError: divided by 0>
ZeroDivisionError
"divided by 0"
["test.rb:2:in `/'", "test.rb:2:in `<main>'"]
発生した例外の種類によって処理を変える
rescue のあとに例外の種類を指定することで、発生した例外の種類によって処理を変えることができます。
以下は「ZeroDivisionError」と、「NameError」または「RuntimeError」が発生したときで処理を変える例。
begin
p 1/0
rescue ZeroDivisionError
p "エラー1"
rescue NameError, RuntimeError # 2つまとめて指定することもできる
p "エラー2"
end
"エラー1"
例外が発生しなかったときだけ実行するコードを追加する(else の使用例)
以下は上のプログラムに else
を付け加えた例。
begin
の下にあるコードに例外が発生しないので、else
の下にあるコードが最後に実行されます。
begin
p "テスト"
rescue
p "例外が発生しました"
else
p "例外が発生しませんでした"
end
"テスト"
"例外が発生しませんでした"
例外の有無に関わらず 最後に実行したいプログラムを追加する(ensure の使用例)
ensure を使うと、例外の有無に関係なく 最後に必ず実行したいコードを追加することができます。
以下は例外が発生しない場合の例。ensure
の下にある p "プログラム終了"
のコードが実行されます。
begin
p "テスト"
rescue
p "例外が発生しました"
else
p "例外が発生しませんでした"
ensure
p "プログラム終了"
end
"テスト"
"例外が発生しませんでした"
"プログラム終了
こちらは例外が発生した場合の例。こちらも ensure
の下にある p "プログラム終了"
のコードが実行されていることが確認できます。
begin
p 1/0
rescue
p "例外が発生しました"
else
p "例外が発生しませんでした"
ensure
p "プログラム終了"
end
"例外が発生しました"
"プログラム終了"
ensure の使い道として、例えばファイルを開いて作業を行うプログラムの場合、実行中に例外が発生してもしなくても、必ず最後にファイルを閉じておく、といったことができます。
f = File.open('test.txt') # ファイルを開く
begin
# ファイルに対して行いたい処理
rescue
# 例外が発生したときの処理
ensure
f.close if f # ファイルを閉じる
end
意図的に例外を発生させる(raise の使用例)
以下は意図的に例外を発生させるプログラム例。
raise
の行で例外が発生します。
begin
raise
rescue
p "例外が発生しました"
end
"例外が発生しました"
raise のあとに例外の種類を指定することもできます。
以下は「NameError」を発生させる例。
begin
raise NameError
rescue => e
p "例外が発生しました"
p e
end
"例外が発生しました"
#<NameError: NameError>
例外のメッセージを指定することもできます。
以下は種類が「NameError」で、メッセージが「エラーのテスト」の例外を発生させる例。
begin
raise NameError, "例外のテスト"
rescue => e
p "例外が発生しました"
p e
end
"例外が発生しました"
#<NameError: 例外のテスト>
以下のように、例外のメッセージのみを指定することもできます。その場合、例外の種類は「RuntimeError」となります。
begin
raise "例外のテスト"
rescue => e
p "例外が発生しました"
p e
end
"例外が発生しました"
#<RuntimeError: 例外のテスト>
例外が発生したら、再度 処理をやり直す(retry の使用例)
retry を使うと、begin
以下に記述した処理を 再度やり直すことができます。
以下は例外が発生したら、3回まで処理をやり直す例。
count = 0
begin
raise
rescue
count += 1
p "処理失敗(#{count}回目)"
if count < 3
retry
end
p "プログラム終了"
end
"処理失敗(1回目)"
"処理失敗(2回目)"
"処理失敗(3回目)"
"プログラム終了"
外部と通信するときに、接続に失敗したら再度 接続する、といった処理を記述するときに便利です。
メソッド全体に例外処理を設ける
メソッド全体に例外処理を設ける場合は、begin
や end
を省略することができます。
以下のプログラムを例にしてみましょう。
def test
begin
p 1/0
rescue
p "例外が発生しました"
end
end
上のプログラムは以下のように書くこともできます。記述を減らすことができ、階層を深くする必要がなくなります。
def test
p 1/0
rescue
p "例外が発生しました"
end
メソッドについて詳しくはこちら。
あまり見かけませんが、メソッドだけでなくクラスの場合でも同様の形で記述することができます。
まとめ
以上、Rubyでの例外処理の使い方でした!
ここまでの内容をまとめておきます。
- 例外処理は「begin … rescue … else … ensure … end」のように記述する。
begin
の下に、通常 実行したいコードを書く。rescue
の下に、例外が起こったときに実行するコードを書く。else
の下に、例外が起こらなかったときだけ実行するコードを書く。ensure
の下に、例外の有無に関わらず 最後に実行したいコードを書く。rescue => 変数名
のようにすると、指定した変数名でエラー情報を取得できる。rescue 例外の種類
のようにすると、発生した例外の種類によって処理を変えることができる。- raise を使って、例外を意図的に起こすことができる。
- retry を使って、
begin
の下に記述した処理を 再度やり直すことができる。 - メソッド全体に例外処理を設ける場合は、
begin
やend
を省略することもできる。