异常处理是开发过程中经常要面对的问题,基本所有高级语言都有自己的异常处理系统,ruby也不例外,而且使用起来也非常简单。
ruby中异常的抛出是使用的raise方法,记住哦,这是个方法,由ruby Kernel提供的,而不是关键字,同时ruby也为这个方法提供了一个别名fail,可以用fail代替raise,抛出异常的例子如下:
以上代码中的raise可以使用别名fail代替,在没有明确的给出异常类型时,ruby默认抛出RuntimeError,其中最后一个例子抛出的信息包含了当前错误所在的文件,行数已经所在的方法的信息,这些信息都存储在caller这个数组中,里面包含了方法调用者的相关 信息,第一个元素包含了方法的调用者的信息,第二个信息包含了方法调用者的调用者的信息,以此类推。这个数组在我们想知道异常是在哪个地方的哪个调用被抛 出的时候非常有用的。
从上面的代码可以看出,caller记录了每个调用者所在的文件名,行数以及方法。
上面讲解了关于ruby异常抛出的方式以及caller数组的作用,接下来我们来了解一下ruby中是如何进行异常的捕捉的,在java中,异常的捕捉是在try ... catch当中进行,而ruby则是在begin ... end代码块中进行异常的捕捉,在该代码块中使用rescue关键字进行捕捉异常类型,注意哦,这个是关键字,而不是方法。
以上代码就是一个大概的捕捉异常的例子,在begin和end代码块中通过rescue进行异常类型的捕捉然后进行适当的处理,可是如果抛出的异常类型并没有显示的捕捉如何处理呢?那就是在最后使用else,如下:
这时又有一个问题,如果我想获取异常信息又该如何做呢?请看下面的代码:
通过rescue => variable的方式,就可以将异常保存为一个variable了。又解决了一个问题,还有什么问题呢?啊,对了,在java的使用当中,比如使用Connection进行数据库连接后,最后一定要进行资源的清理,都是在finally块当中进行的,可是在ruby中又如何进行这些资源的清理呢?看看下面的代码:
从上面代码我们看到,ruby提供了一个关键字ensure,它的作用和java中的finally一样,无论任何异常,该关键字下的代码都必然会在退出代码块前执行。同时,ruby还提供恢复功能,如果在抛出异常并进行异常处理后我们需要进行恢复工作,那就是使用retry就会重新执行代码块了。
上面提到,异常的捕捉处理必须在begin-end代码块中进行,那是不是无论什么时候都要书写begin-end这两个关键字呢?其实也不是,在ruby中,方法实际上就是一个隐式的begin-end代码块,所以在方法中进行异常的捕捉和处理,可以省略begin。
本文参考《The Ruby Way》一书所写,如有不足的地方,请各位指正,谢谢!
ruby中异常的抛出是使用的raise方法,记住哦,这是个方法,由ruby Kernel提供的,而不是关键字,同时ruby也为这个方法提供了一个别名fail,可以用fail代替raise,抛出异常的例子如下:
raise
#
抛出一个默认的RuntimeError
raise " Some error message " # 抛出一个消息为"Some error message"的RuntimeError
raise ArgumentError # 抛出一个无消息的ArgumentError
raise ArgumentError, " Bad data " # 抛出一个消息为"Bad data"的ArgumentError
raise ArgumentError.new( " Bad data " ) # 同上
raise ArgumentError ArgumentError, " Bad data " , caller[0] # 抛出一个包含消息的格式为filename:line 或者 filename:line:in 'method' 的异常
raise " Some error message " # 抛出一个消息为"Some error message"的RuntimeError
raise ArgumentError # 抛出一个无消息的ArgumentError
raise ArgumentError, " Bad data " # 抛出一个消息为"Bad data"的ArgumentError
raise ArgumentError.new( " Bad data " ) # 同上
raise ArgumentError ArgumentError, " Bad data " , caller[0] # 抛出一个包含消息的格式为filename:line 或者 filename:line:in 'method' 的异常
以上代码中的raise可以使用别名fail代替,在没有明确的给出异常类型时,ruby默认抛出RuntimeError,其中最后一个例子抛出的信息包含了当前错误所在的文件,行数已经所在的方法的信息,这些信息都存储在caller这个数组中,里面包含了方法调用者的相关 信息,第一个元素包含了方法的调用者的信息,第二个信息包含了方法调用者的调用者的信息,以此类推。这个数组在我们想知道异常是在哪个地方的哪个调用被抛 出的时候非常有用的。
def
func1
puts caller # 打印调用者信息
end
def func2
func1 # 第六行
end
def func3
func2 # 第十行
end
func3 # 最终调用者,十三行
# 运行结果
# test.rb:6:in `func2'
# test.rb:10:in `func3'
# test.rb:13
puts caller # 打印调用者信息
end
def func2
func1 # 第六行
end
def func3
func2 # 第十行
end
func3 # 最终调用者,十三行
# 运行结果
# test.rb:6:in `func2'
# test.rb:10:in `func3'
# test.rb:13
从上面的代码可以看出,caller记录了每个调用者所在的文件名,行数以及方法。
上面讲解了关于ruby异常抛出的方式以及caller数组的作用,接下来我们来了解一下ruby中是如何进行异常的捕捉的,在java中,异常的捕捉是在try ... catch当中进行,而ruby则是在begin ... end代码块中进行异常的捕捉,在该代码块中使用rescue关键字进行捕捉异常类型,注意哦,这个是关键字,而不是方法。
begin
...... # 可能出现异常的代码
rescue errorType1 # 要捕捉的异常类型
...... # 处理异常的代码
rescue errorType2 # 要捕捉的异常类型
...... # 处理异常的代码
end
...... # 可能出现异常的代码
rescue errorType1 # 要捕捉的异常类型
...... # 处理异常的代码
rescue errorType2 # 要捕捉的异常类型
...... # 处理异常的代码
end
以上代码就是一个大概的捕捉异常的例子,在begin和end代码块中通过rescue进行异常类型的捕捉然后进行适当的处理,可是如果抛出的异常类型并没有显示的捕捉如何处理呢?那就是在最后使用else,如下:
begin
...... # 可能出现异常的代码
rescue errorType1 # 要捕捉的异常类型
...... # 处理异常的代码
rescue errorType2 # 要捕捉的异常类型
...... # 处理异常的代码
else
...... # 如果以上代码类型都没有捕捉到,则运行该段代码
end
...... # 可能出现异常的代码
rescue errorType1 # 要捕捉的异常类型
...... # 处理异常的代码
rescue errorType2 # 要捕捉的异常类型
...... # 处理异常的代码
else
...... # 如果以上代码类型都没有捕捉到,则运行该段代码
end
这时又有一个问题,如果我想获取异常信息又该如何做呢?请看下面的代码:
begin
raise ArgumentError, " Bad data "
rescue => err
puts err
end
raise ArgumentError, " Bad data "
rescue => err
puts err
end
通过rescue => variable的方式,就可以将异常保存为一个variable了。又解决了一个问题,还有什么问题呢?啊,对了,在java的使用当中,比如使用Connection进行数据库连接后,最后一定要进行资源的清理,都是在finally块当中进行的,可是在ruby中又如何进行这些资源的清理呢?看看下面的代码:
begin
raise ArgumentError, " Bad data "
rescue => err
puts err
ensure
... # 执行清理工作
end
raise ArgumentError, " Bad data "
rescue => err
puts err
ensure
... # 执行清理工作
end
从上面代码我们看到,ruby提供了一个关键字ensure,它的作用和java中的finally一样,无论任何异常,该关键字下的代码都必然会在退出代码块前执行。同时,ruby还提供恢复功能,如果在抛出异常并进行异常处理后我们需要进行恢复工作,那就是使用retry就会重新执行代码块了。
上面提到,异常的捕捉处理必须在begin-end代码块中进行,那是不是无论什么时候都要书写begin-end这两个关键字呢?其实也不是,在ruby中,方法实际上就是一个隐式的begin-end代码块,所以在方法中进行异常的捕捉和处理,可以省略begin。
本文参考《The Ruby Way》一书所写,如有不足的地方,请各位指正,谢谢!