Ruby异常捕获
当Ruby的代码运行异常时,会抛出异常,我们在开发时随时可能会发生异常,本章节中让我们来了解Ruby中的异常。
1. 什么是异常
在 Ruby 中异常是一种特殊的对象,它是 Exception 实例或这个类的子类。下面引用《Programming Ruby》书中的一个图片。
默认情况下,当程序发生异常,Ruby程序会立即终止。不过我们可以使用异常处理机制来处理程序中遇到的异常,它是一个代码块,当异常发生时,将执行异常处理的代码。
2. raise抛出异常
除了编程异常出现的异常外,我们可以使用raise
来强制抛出一个异常。
实例:
def raise_exception
puts "before raise exception"
raise "This is a exception"
puts "after raise exception"
end
raise_exception
# ---- 输出结果 ----
before raise exception
Traceback (most recent call last):
1: from test.rb:7:in `<main>'
test.rb:3:in `raise_exception': This is a exception (RuntimeError)
解释:由打印我们可以看到,当执行完"before raise exception"的文字输出后,程序抛出了一个异常,这个异常的名称是我们定义的“This is a exception”。
Tips:默认情况下,raise创建RuntimeError类的异常。
我们也可以通过传入异常的类型,来改变raise异常的类型。
实例:
def inverse(x)
raise ArgumentError, 'Argument is not numeric' unless x.is_a? Numeric
1.0 / x
end
puts inverse(2)
puts inverse('not a number')
# ---- 输出结果 ----
0.5
Traceback (most recent call last):
1: from test.rb:6:in `<main>'
test.rb:2:in `inverse': Argument is not numeric (ArgumentError)
解释: 我们在raise
后面增加了需要抛出的异常类型,由输出结果我们可以看到,最后抛出的异常类型为ArgumentError。
3. 异常处理
为了捕获异常处理,我们使用begin-end
将可能发生异常的代码封装它之中,并使用rescue
告诉我们要处理异常的类型。
让我们捕获一下第一个例子的异常。
实例:
def raise_exception
puts "before raise exception"
raise "This is a exception"
puts "after raise exception"
end
begin
raise_exception
rescue Security => e
puts "get the exception"
end
# ---- 输出结果 ----
before raise exception
get the exception
解释:由上面例子我们可以看到,当出现异常时,将立刻执行rescue
后面的语句,而异常中断后面的代码不会执行。
Tips:如图显示大多数异常属于 StandardError,默认情况下,Ruby 的异常捕获只捕获StandardError 的异常。
我们也可以将异常对象映射到rescue
的后面来只获取指定类型的异常。
实例:
def raise_exception
puts "before raise exception"
raise "This is a exception"
puts "after raise exception"
end
begin
raise_exception
rescue SecurityError => e
puts "get the exception"
end
# ---- 输出结果 ----
before raise exception
Traceback (most recent call last):
1: from test.rb:8:in `<main>'
test.rb:3:in `raise_exception': This is a exception (RuntimeError)
解释:由于异常的类型是 StandardError,所以并不会触发异常捕获。
我们也可以对多种异常类型进行捕获。它的形式如下显示,当异常类型不匹配时,会依次向下进行匹配,如果不发生异常,将执行else
下面的语句。
begin
# -
rescue OneTypeOfException
# -
rescue AnotherTypeOfException
# -
else
# No exceptions
end
实例:
def raise_exception
puts "before raise exception"
raise "This is a exception"
puts "after raise exception"
end
begin
raise_exception
rescue SecurityError => e
puts "get the SecurityError"
rescue StandardError => e
puts "get the StandardError"
end
# ---- 输出结果 ----
before raise exception
get the StandardError
解释:当抛出异常后,首先将异常类型和 SecurityError 进行对比,发现不符合继续查找下一个,第二个异常类型 StandardError 和当前异常相符合,于是执行了它下面的语句。
4. retry
在捕获到异常并执行rescue
下的语句时,我们还可以使用retry
来重新执行发生异常的代码。
num = 0
begin
puts "current num = #{num}"
raise if num < 3
puts "finished!"
rescue
num += 1
puts 'retry!'
retry
end
# ---- 输出结果 ----
current num = 0
retry!
current num = 1
retry!
current num = 2
retry!
current num = 3
finished!
解释:当num
小于 3 时代码运行会一直触发异常,每次当异常发生时,执行num
的累加操作并执行retry,直到 num
等于 3 不抛出异常代码结束。
5. 小结
本章节我们学习了什么是异常,使用raise
强制抛出异常,使用begin-end
+rescue
来捕获异常,以及使用retry
重新运行出现异常的代码。