在Ruby中为什么使用rescue Exception => e是不好的风格?

摘要

rescue Exception => e会捕获所有异常,这往往不是我们希望的行为。在处理异常时,应该只处理我们知道如何处理的异常。通常情况下,应该使用更具体的异常类进行捕获。如果需要访问异常对象,可以使用rescue => e

内容

Exception是Ruby异常继承层次结构的根,当使用rescue Exception时,实际上是捕获了所有的异常,包括SyntaxErrorLoadErrorInterrupt等子类。这样的捕获行为可能产生意想不到的结果。

例如,如果捕获了Interrupt异常,用户将无法使用CTRL+C来中止程序。捕获SignalException异常将导致程序无法正确响应信号,除非使用kill -9来终止程序。捕获SyntaxError意味着eval失败时不会触发错误。

以下示例程序展示了捕获Exception可能带来的问题:

1loop do
2  begin
3    sleep 1
4    eval "djsakru3924r9eiuorwju3498 += 5u84fior8u8t4ruyf8ihiure"
5  rescue Exception
6    puts "I refuse to fail or be stopped!"
7  end
8end

另外值得注意的是,捕获Exception并不是默认行为。在没有指定异常类的情况下,rescue语句默认会捕获StandardError。通常情况下,应该明确指定更具体的异常类,而不是捕获Exception。捕获Exception会扩大异常范围,可能导致严重的后果,并且使问题排查变得非常困难。

对于需要捕获StandardError并且需要访问异常对象的情况,可以使用下面的语法:

1begin
2  # ...
3rescue => e
4  # ...
5end

这等效于:

1begin
2  # ...
3rescue StandardError => e
4  # ...
5end

为了记录和报告目的而捕获Exception是少数几个可以接受的情况之一,在这种情况下,应该立即重新抛出异常,避免潜在的问题。

1begin
2  # ...
3rescue Exception => e
4  # 记录日志
5  raise # 没有足够的救生艇 ;)
6end

总结

捕获Exception是一个捕获所有异常的行为,这往往不是我们期望的行为。在处理异常时,应该只处理我们知道如何处理的异常。通常情况下,应该使用更具体的异常类进行捕获。如果需要访问异常对象,可以使用rescue => e。使用rescue Exception会扩大异常范围,可能导致严重的后果,并使问题排查变得困难。保持代码的可读性和一致性有助于准确定位和解决问题。


相关文章推荐