请不要在Ruby直接使用Exception来捕捉异常!


在这之前你也许已经听说过这个。的确这是一个很好的建议,除非你已经知道,否则它会让人感到困惑。接下来让我们来分解这个,看看它到底是什么意思。

你可能知道在Ruby中,你可以像这样拯救异常:

begin
  do_something()
rescue => e
  puts e # e is an exception object containing info about the error. 
end
And you can rescue specific errors by providing the classname of the error.

begin
  do_something()
rescue ActiveRecord::RecordNotFound => e
  puts e # Only rescues RecordNotFound exceptions, or classes that inherit from RecordNotFound
end

在Ruby中的每种类型的异常都只是一个类。在上面的例子中,ActiveRecord::RecordNotFound就是遵循某些约定的类的名称。
在这里这很重要,因为当你捕捉RecordNotFound时,你也可以捕捉从它继承的任何异常。
为什么你不应该使用Exception,在很多时候我们需要快速定位错误本身或者对不同的错误有不同的处理方式。此时特定的异常捕捉就更加重要。


  • 语法错误
  • 方法未定义
  • 网络问题

因为Ruby内部使用了一些异常。他们与你的应用程序没有任何关系,吞下它们会导致不好的事情发生。

这里有几个大的:


  • SignalException::Interrupt  - 如果你解决了这个问题,你不能通过点击control-c来退出你的应用程序
  • ScriptError::SyntaxError - 吞咽语法错误意味着像puts(忘记了某些东西)这样的事情将会失败
  • NoMemoryError - 想知道当你的程序在耗尽所有内存后继续运行时会发生什么?
begin
  do_something()
rescue Exception => e
  # Don't do this. This will swallow every single exception. Nothing gets past it. 
end
我猜你并不是真的想要吞下这些系统级别的异常。很多时候您只想捕获所有应用程序级别的错误。这些来自您代码中的错误。

在这里幸运的是,这有一个简单的方法。

Rescue StandardError Instead - 您关心的所有异常都是从StandardError继承的。 


  • NoMethodError - 当您尝试调用不存在的方法时引发 
  • TypeError - 由类型转换引起的事件 
  • RuntimeError - 谁会忘记旧的RuntimeError? 

为了解决这些错误,你需要捕捉StandardError。你可以通过写这样的事情来做到这一点:

begin
  do_something()
rescue StandardError => e
  # Only your app's exceptions are swallowed. Things like SyntaxErrror are left alone. 
end
此时如果没有指定异常类,ruby会假定您的意思是StandardError。所以下面的代码和上面的代码是一样的:
begin
  do_something()
rescue => e
  # This is the same as rescuing StandardError
end
如果你正在创建自己的自定义异常, 那么我们创建的自定义异常其实也应该继承StandardError.
这意味着你应该总是继承自StandardError,而不是从Exception继承。继承Exception是不好的,因为它打破了救援的预期行为。人们会认为他们正在拯救所有的应用程序级别的错误,但是你将会继续前进。
class SomethingBad < StandardError
end
raise SomethingBad

由于Ruby的异常是在类的层次中实现的,因此可以将它看作布局。

下面是Ruby标准库附带的异常类列表。像rails这样的第三方gems会为这个图表添加额外的异常类,但它们都将继承这个列表中的某个类。

Exception
 NoMemoryError
 ScriptError
   LoadError
   NotImplementedError
   SyntaxError
 SignalException
   Interrupt
 StandardError
   ArgumentError
   IOError
     EOFError
   IndexError
   LocalJumpError
   NameError
     NoMethodError
   RangeError
     FloatDomainError
   RegexpError
   RuntimeError
   SecurityError
   SystemCallError
   SystemStackError
   ThreadError
   TypeError
   ZeroDivisionError
 SystemExit
 fatal