Ruby 开发(六)- 异常处理

504 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第15天,点击查看活动详情

一、异常处理机制

所谓异常,就是指在程序运行过程中由于硬件设备问题或者软件设计错误导致的程序错误时间,在程序中通过抛出异常来处理错误。

Ruby 中抛出异常就意味着终止当前运行的程序,并且调用方法进行异常处理,Ruby 中抛出的异常是 Exception 类或者子类。

Ruby 中常见的异常类型如下:

异常类型异常说明
RuntimeError运行时异常,当调用了 raise 却未指定异常时会引发该异常
NoMethodError对象找不到方法时,抛出该异常
NameError解释器遇到一个不能解析为变量或者
IOError当读取到关闭的流、写入或者只读的流均会发生该异常
Errorno::error与文件 IO 相关的一组错误
TypeError方法遇到不能处理的参数,参数类型错误
ArgumentError传递参数错误

Ruby 程序运行过程中,一旦出现异常系统会自动抛出,需要使用 begin...end 代码块将要保护的代码放到内部,通过 rescue 关键字来捕获异常。

Ruby 中的异常主要依赖于 rescue 和 ensure 来完成,但是两者的任务是不同的,rescue 块主要是将程序从异常中解救出来,ensure 主要是用于保证系统的资源回收。

puts "使用 rescue 来捕获异常"

begin
  class Swim
    def swimming name
      @name = name
      puts "#{@name} is swimming"
    end
  end

  swim = Swim.new
  swim.swimming
rescue
  puts "swimming 函数参数未传,出现异常"
end

执行上述代码,输出结果如下:

使用 rescue 来捕获异常
swimming 函数参数未传,出现异常

如果不使用 begin...end 和 rescue 捕获异常,则会直接报错

	1: from ruby-exception/ex1.rb:26:in `<main>'
/ruby-exception/ex1.rb:19:in `swimming': wrong number of arguments (given 0, expected 1) (ArgumentError)
不使用 rescue 捕获异常

在 Ruby 代码中也可以添加多个异常处理代码块来捕获不同的异常。

begin
  class Fly
    def flying speed
      @speed = speed
      puts "祖国人正在飞行,时速 #{@speed}"
    end
  end

  fly = Fly.new
  # 不传参数,抛出异常
  fly.flying
  # 调用未定义的方法或者属性,抛出异常
  fly.info

rescue NoMethodError
  puts "调用未定义的方法或者属性,抛出异常"

rescue ArgumentError
  puts "不传参数,抛出异常"

end

上述代码中定义类两种异常,分别是 NoMethodError 和 ArgumentError,通过 rescue 关键字来捕获异常。执行上述代码,输出结果如下:

不传参数,抛出异常

虽然说指定了多个捕获异常,但是仍会只捕获遇到的以一个异常与 rescue 异常类型所处的位置无关。

如果想要获取异常类中的异常信息,首先要采用 rescue 异常类 => 实例名 的方式来获取引发异常的实例,然后通过实例调用异常类的方法获取发生异常的信息。

def zulu
  puts "zulu 方法"
end

begin
  zulu "a", "b"
rescue Exception => e
  puts "出现异常,异常信息如下:"
  puts "#{e.backtrace}"
  puts "#{e.to_s}"
  puts "#{e.message}"
end

执行上述代码,输出结果如下:

出现异常,异常信息如下:
["/ruby-exception/ex3.rb:1:in `zulu'", "/ruby-exception/ex3.rb:6:in `<main>'"]
wrong number of arguments (given 2, expected 0)
wrong number of arguments (given 2, expected 0)

根据输出的系统报错信息可以很明显的看出报错原因是”方法期望 0 个参数,但是给了 2 个“。

获取异常类中常用的方法主要有 backtrace 方法,实例化的 new 方法、to_s 方法以及 message 方法

二、raise 抛出异常

使用 raise 关键字加上要跑出的异常类的名称,就可以在程序中显示这个异常,并且可以为 raise 添加第二个参数既自定义的异常信息

def zulu
  raise NameError, "这是自定义的 zulu 方法抛出的异常信息"
end

zulu

执行上述代码,输出结果如下:

Traceback (most recent call last):
	1: from /ruby-exception/ex4.rb:5:in `<main>'
/ruby-exception/ex4.rb:2:in `zulu': 这是自定义的 zulu 方法抛出的异常信息 (NameError)

针对 raise 抛出的异常当然也可以使用 rescue 捕获并输出自定义的异常信息。

def info
  raise ArgumentError, "这是自定义的 info 方法抛出的异常信息"
end

# 捕获异常信息
begin
  info
rescue ArgumentError => e
  puts "输出捕获的异常对象:#{e}"
  puts "异常对象中的异常信息为:#{e.message}"
  puts "出现异常的位置为:#{e.backtrace}"
end

执行上述代码,输出结果如下:

输出捕获的异常对象:这是自定义的 info 方法抛出的异常信息
异常对象中的异常信息为:这是自定义的 info 方法抛出的异常信息
出现异常的位置为:["/ruby-exception/ex5.rb:2:in `info'", "/ruby-exception/ex5.rb:7:in `<main>'"]