💡 この記事でわかること
- 例外(エラー)とは何か、なぜプログラムが止まるのか
begin・rescueでエラーをキャッチして処理を続ける方法- エラーの種類を指定してキャッチする方法と、
rescue => eでのメッセージ取得 else・ensureの役割、raiseでわざと例外を出す方法- メソッド定義では
beginを省略できること、初心者がよく出会うエラー一覧
1. 例外(エラー)とは?
例外とは、
👉 プログラムの実行中に発生する「想定外の事態」のことです。エラーと呼ばれることも多いです。
たとえば、次のコードは「数字」を期待していますが、利用者が abc と入力すると例外が発生します。
print "数字を入力: "
num = Integer(gets.chomp)
puts num * 2
# 「abc」と入力すると…
# `Integer': invalid value for Integer(): "abc" (ArgumentError)👉 例外が発生すると、そこでプログラムは強制的に停止し、それ以降の処理は実行されません。この「停止」を防ぎ、エラーが起きても処理を続けられるようにするのが例外処理です。
💡 gets.chomp.to_i はエラーにならず 0 を返しますが、Integer() は変換できないと例外を出します。「不正な入力をはっきりエラーにしたい」ときは Integer() を使い、例外処理と組み合わせます。
👉 Rubyのデータ型(型変換・to_iとの違い)についての記事はこちら
2. begin・rescue の基本
begin のブロックに「エラーが起きるかもしれない処理」、rescue のブロックに「エラーが起きたときの処理」を書き、end で閉じます。
begin
print "数字を入力: "
num = Integer(gets.chomp)
puts "2倍すると #{num * 2} です"
rescue ArgumentError
puts "数字を入力してください"
end
puts "プログラムは続行します"beginの中でエラーが起きなければ、rescueはスキップされる- エラーが起きると、その時点で
rescueに移る(beginの残りは実行されない) rescueで処理したあとは、プログラムは止まらずに先に進む
3. エラーの種類を指定する
rescue ZeroDivisionError のように書くと、その種類のエラーだけをキャッチします。想定していない別のエラーはそのまま止まってくれるので、原因に気づけます。
begin
result = 10 / 0
rescue ZeroDivisionError
puts "0で割ることはできません"
end💡 種類を書かずに rescue だけにすると、StandardError という「よくあるエラーのグループ」をまとめてキャッチします。rescue Exception と書くと、Ctrl + C による中断など、本来止めるべきものまで拾ってしまうため、初心者のうちは rescue(種類なし)か rescue StandardError にとどめてください。
複数の種類を分けて処理する
begin
a = Integer(gets.chomp)
b = Integer(gets.chomp)
puts a / b
rescue ArgumentError
puts "数字を入力してください"
rescue ZeroDivisionError
puts "0では割れません"
endエラーの内容を受け取る(rescue => e)
begin
value = Integer("abc")
rescue ArgumentError => e
puts "エラー内容: #{e.message}"
# エラー内容: invalid value for Integer(): "abc"
end👉 rescue エラー名 => e と書くと、エラーの詳細情報がオブジェクト e に入ります。e.message でメッセージ、e.class でエラーの種類を取り出せます。ログに残したり、原因を表示したりするときに使います。
4. else と ensure
- else:
beginで例外が起きなかったときだけ実行される - ensure:例外の有無にかかわらず必ず実行される(後片付け用。他の言語の
finallyにあたる)
begin
num = Integer("10")
rescue ArgumentError
puts "変換に失敗しました"
else
puts "変換に成功: #{num}" # 例外がなかったときだけ
ensure
puts "処理を終了します" # 必ず実行される
end5. メソッドの中では begin を省略できる
👉 メソッド定義(def 〜 end)の中では、begin を書かずに rescue を使えます。メソッド全体が begin のかわりになるイメージです。
def to_number(text)
Integer(text)
rescue ArgumentError
0 # 変換できないときは 0 を返す
end
puts to_number("42") # 42
puts to_number("abc") # 0👉 Rubyのメソッド(def・引数・戻り値)についての記事はこちら
6. raise でわざと例外を出す
raise を使うと、自分で例外を発生させることができます。メソッドに渡された値がおかしいときなど、「これは想定外だ」と明示的に知らせたい場面で使います。
def set_age(age)
raise ArgumentError, "年齢は0以上で指定してください" if age < 0
age
end
puts set_age(20) # 20
puts set_age(-5) # ArgumentError: 年齢は0以上で指定してくださいraise エラー名, "メッセージ":種類を指定して例外を出すraise "メッセージ":種類を省略するとRuntimeErrorになる
7. 例外処理を使うときの注意
👉 「エラーを消すため」だけに例外処理を使うのは避けましょう。次のように何でもキャッチして何もしないと、本来直すべきバグまで隠れてしまい、原因がまったく分からなくなります。
# 悪い例:すべての例外を握りつぶしている
begin
do_something
rescue => e
# 何もしない
end- キャッチするエラーは具体的な種類を指定する(
rescue ArgumentErrorなど) - 例外処理は「起こりうると分かっていて、対処法があるエラー」に対して使う
- 原因不明のエラーは、むしろ止まってくれたほうが気づける
8. よく出会うエラー一覧
| エラー名 | 起きる状況 |
|---|---|
| NoMethodError | その値に無いメソッドを呼んだ。nil に対して呼んでしまう例が多い |
| NameError | 定義していない変数・定数を使った |
| ArgumentError | 引数の個数が違う、Integer("abc") など値が不正 |
| TypeError | "文字" + 5 など、型に合わない操作 |
| ZeroDivisionError | 整数を 0 で割り算した |
| KeyError | hash.fetch(:x) で存在しないキーを指定した |
| Errno::ENOENT | 存在しないファイルを開こうとした |
💡 配列の範囲外の番号(arr[100])やハッシュの無いキー(hash[:x])は、Rubyでは例外にならず nil が返ります。その nil に対してうっかりメソッドを呼んで NoMethodError になる、というのが初心者に一番多いパターンです。
👉 エラーメッセージは1行目が最も重要です。「どのファイルの何行目で、どのエラーが起きたか」が書かれているので、まずはそこを落ち着いて読みましょう。
9. まとめ
- 例外が起きるとプログラムは停止する。begin・rescueで止まらずに対処できる
- キャッチするエラーは種類を具体的に指定する(
rescue ArgumentError) rescue => eでエラーの詳細を受け取れる(e.message/e.class)- else=例外がなかったとき、ensure=必ず実行
- メソッドの中では
beginを省略できる。raiseで自分から例外を出せる rescue Exceptionや何もしないrescueで握りつぶすのは避ける
👉 まずは Integer(gets.chomp) を begin・rescue ArgumentError で囲むところから使ってみましょう。ユーザーの入力を扱うプログラムでは、ほぼ必ず登場するパターンです。