言語
日本語
English

Caution

お使いのブラウザはJavaScriptが無効になっております。
当サイトでは検索などの処理にJavaScriptを使用しています。
より快適にご利用頂くため、JavaScriptを有効にしたうえで当サイトを閲覧することをお勧めいたします。

Ruby辞典

  1. トップページ
  2. Ruby辞典
  3. 例外クラス / StandardError / RuntimeError

例外クラス / StandardError / RuntimeError

対応: Ruby 1.8(2003)

Rubyには用途別に分類された例外クラスが用意されています。独自の例外クラスを定義して使うこともできます。

構文

# 独自例外クラスを定義します。
class CustomError < StandardError
  def initialize(msg = "デフォルトメッセージ")
    super
  end
end

# 独自例外を発生させます。
raise CustomError
# 以下は発展的な使い方です。
raise CustomError, "詳細なメッセージ"
raise CustomError.new("メッセージ")

# 例外クラスの階層を確認します。
puts error_class.ancestors

主要な例外クラス

例外クラス概要
StandardError一般的なエラーの基底クラスです。独自例外はこれを継承します。
RuntimeError『raise』にクラスを指定しない場合に発生するデフォルトの例外です。
TypeError型が不正な場合に発生します(例:文字列と整数の加算)。
ArgumentError引数の数や値が不正な場合に発生します。
NameError未定義の変数・メソッド名を参照した場合に発生します。
NoMethodError存在しないメソッドを呼び出した場合に発生します(NameError のサブクラス)。
ZeroDivisionError整数をゼロで除算した場合に発生します。
IOErrorファイルやストリーム操作に失敗した場合に発生します。
Errno::ENOENTファイルやディレクトリが見つからない場合に発生します。

サンプルコード

sample_exception_class.rb
# 独自例外クラスを定義します。
class ValidationError < StandardError
  attr_reader :field_name

  def initialize(field_name, msg = nil)
    @field_name = field_name
    super(msg || "#{field_name}の値が不正です。")
  end
end

class AgeError < ValidationError; end

# 独自例外を発生させて補足します。
def register_user(name, age)
  raise ValidationError.new("名前"), "名前は必須です。" if name.empty?
  raise AgeError.new("年齢"), "年齢は0以上を指定してください。" if age < 0

  puts "#{name}(#{age}歳)を登録しました。"
end

begin
  register_user("桐生一馬", 37)
  register_user("", 20)
rescue AgeError => e
  puts "年齢エラー: #{e.message}"
rescue ValidationError => e
  puts "バリデーションエラー[#{e.field_name}]: #{e.message}"
end
ruby exception_class.rb
桐生一馬(37歳)を登録しました。
バリデーションエラー[名前]: 名前は必須です。

複数の独自例外クラスを定義してrescueで使い分けます。サブクラスを先に書かないと親クラスのrescueに吸収されてしまう点に注意してください。

sample_exception_class2.rb
# 例外クラスの階層を定義します。
class AppError < StandardError; end
class NetworkError < AppError; end
class TimeoutError < NetworkError; end

def fetch_data(url)
  raise TimeoutError, "接続がタイムアウトしました: #{url}" if url.include?("slow")
  raise NetworkError, "ネットワークに接続できません: #{url}" if url.include?("bad")
  raise AppError, "アプリケーションエラーが発生しました。"
end

# サブクラスを先にrescueします(逆順だと親クラスに吸収されます)。
["https://slow.example.com", "https://bad.example.com", "https://example.com"].each do |url|
  begin
    fetch_data(url)
  rescue TimeoutError => e
    puts "タイムアウト: #{e.message}"
  rescue NetworkError => e
    puts "ネットワーク障害: #{e.message}"
  rescue AppError => e
    puts "アプリエラー: #{e.message}"
  end
end
ruby exception_class2.rb
タイムアウト: 接続がタイムアウトしました: https://slow.example.com
ネットワーク障害: ネットワークに接続できません: https://bad.example.com
アプリエラー: アプリケーションエラーが発生しました。

独自例外クラスで『message』メソッドをオーバーライドすると、エラーコードや追加情報をメッセージに組み込めます。

sample_exception_class3.rb
# messageメソッドをオーバーライドして書式付きメッセージを返します。
class ApiError < StandardError
  attr_reader :code, :endpoint

  def initialize(code, endpoint, msg = nil)
    @code     = code
    @endpoint = endpoint
    super(msg || "HTTPエラー")
  end

  def message
    "[#{@code}] #{super} — #{@endpoint}"
  end
end

begin
  raise ApiError.new(404, "/api/characters/999")
rescue ApiError => e
  puts e.message
  puts "コード: #{e.code}"
  puts "エンドポイント: #{e.endpoint}"
end
ruby exception_class3.rb
[404] HTTPエラー — /api/characters/999
コード: 404
エンドポイント: /api/characters/999

『retry』と組み合わせて、ネットワーク系の例外を一定回数だけ再試行する実装例です。

sample_exception_class4.rb
class RetryableError < StandardError; end

MAX_RETRIES = 3

def unstable_operation(attempt)
  raise RetryableError, "一時的なエラーです(試行 #{attempt})" if attempt < 3
  "成功"
end

retries = 0
begin
  result = unstable_operation(retries + 1)
  puts result
rescue RetryableError => e
  retries += 1
  puts "リトライ #{retries}: #{e.message}"
  retry if retries < MAX_RETRIES
  puts "最大リトライ回数に達しました。"
end
ruby exception_class4.rb
リトライ 1: 一時的なエラーです(試行 1)
リトライ 2: 一時的なエラーです(試行 2)
成功

概要

Rubyの例外クラスは『Exception』を頂点とする階層構造になっています。通常は『StandardError』のサブクラスを使い、独自例外も『StandardError』を継承して定義します。

独自例外クラスを定義すると、エラーの種類を明確に区別でき、呼び出し側で適切に対処できます。『rescue Exception』と書くと『SignalException』や『SystemExit』など終了シグナルまで補足してしまい、『Ctrl+C』でプログラムを終了できなくなります。基本的に『rescue StandardError』か、特定のサブクラスを指定してください。

記事の間違いや著作権の侵害等ございましたらお手数ですがまでご連絡頂ければ幸いです。