在Ruby中为什么使用rescue Exception => e
是不好的风格?
摘要
rescue Exception => e
会捕获所有异常,这往往不是我们希望的行为。在处理异常时,应该只处理我们知道如何处理的异常。通常情况下,应该使用更具体的异常类进行捕获。如果需要访问异常对象,可以使用rescue => e
。
内容
Exception
是Ruby异常继承层次结构的根,当使用rescue Exception
时,实际上是捕获了所有的异常,包括SyntaxError
、LoadError
和Interrupt
等子类。这样的捕获行为可能产生意想不到的结果。
例如,如果捕获了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
会扩大异常范围,可能导致严重的后果,并使问题排查变得困难。保持代码的可读性和一致性有助于准确定位和解决问题。