error raise if error.message != "Oops"" />
牛骨文教育服务平台(让学习变的简单)
  • 使用 fail 方法来抛出异常。仅在捕捉到异常时使用 raise 来重新抛出异常(因为没有失败,所以只是显式地有目的性地抛出一个异常)

    begin
     fail "Oops";
    rescue => error
      raise if error.message != "Oops"
    end
    
  • 如果 fail/raise 只有两个参数,无需显性指定 RuntimeError

    # 差
    fail RuntimeError, "message"
    
    # 好——默认就是 RuntimeError
    fail "message"
    
  • 将异常类和消息作为参数给 fail/raise ,而不是异常类的的实例。

    # 差
    fail SomeException.new("message")
    # 无法使用 `fail SomeException.new("message"), backtrace`.
    
    # 好
    fail SomeException, "message"
    # 可以使用 `fail SomeException, "message", backtrace`.
    
  • 永远不要从 ensure 区块返回。如果你显式地从 ensure 区块中的一个方法返回,那么这方法会如同没有异常般的返回。实际上,异常会被默默丢掉。

    def foo
      begin
        fail
      ensure
        return "very bad idea"
      end
    end
    
  • 尽可能使用隐式的 begin 区块。

    # 差
    def foo
      begin
        # 此处放主要逻辑
      rescue
        # 错误处理放在此处
      end
    end
    
    # 好
    def foo
      # 此处放主要逻辑
    rescue
      # 错误处理放在此处
    end
    
  • 通过 contingency 方法 (一个由 Avdi Grimm 创造的词) 来减少 begin 区块的使用。

    # 差
    begin
      something_that_might_fail
    rescue IOError
      # 处理 IOError
    end
    
    begin
      something_else_that_might_fail
    rescue IOError
      # 处理 IOError
    end
    
    # 好
    def with_io_error_handling
       yield
    rescue IOError
      # 处理 IOError
    end
    
    with_io_error_handling { something_that_might_fail }
    
    with_io_error_handling { something_else_that_might_fail }
    
  • 不要抑制异常。

    begin
      # 这里发生了一个异常
    rescue SomeError
      # 拯救子句完全没有做事
    end
    
    # 差
    do_something rescue nil
    
  • 避免使用 rescue 的修饰符形式。

    # 差 - 这捕捉了所有的 StandardError 异常。
    do_something rescue nil
    
  • 不要为了控制流程而使用异常。

    # 差
    begin
      n / d
    rescue ZeroDivisionError
      puts "Cannot divide by 0!"
    end
    
    # 好
    if d.zero?
      puts "Cannot divide by 0!"
    else
      n / d
    end
    
  • 避免救援 Exception 类别。这会把信号困住,并呼叫 exit,导致你需要 kill -9 进程。

    # 差
    begin
      # 呼叫 exit 及杀掉信号会被捕捉(除了 kill -9)
      exit
    rescue Exception
      puts "you didn"t really want to exit, right?"
      # 异常处理
    end
    
    # 好
    begin
      # 一个不明确的 rescue 子句捕捉的是 StandardError,
      #   而不是许多编程者所设想的 Exception。
    rescue => e
      # 异常处理
    end
    
    # 也好
    begin
      # 这里发生一个异常
    
    rescue StandardError => e
      # 异常处理
    end
    
  • 把较具体的异常放在救援串连的较上层,不然它们永远不会被拯救。

    # 差
    begin
      # 一些代码
    rescue Exception => e
      # 一些处理
    rescue StandardError => e
      # 一些处理
    end
    
    # 好
    begin
      # 一些代码
    rescue StandardError => e
      # 一些处理
    rescue Exception => e
      # 一些处理
    end
    
  • 在 ensure 区块中释放你的程式的外部资源。

    f = File.open("testfile")
    begin
      # .. 处理
    rescue
      # .. 错误处理
    ensure
      f.close unless f.nil?
    end
    
  • 倾向使用标准库的异常类而不是导入新的异常类。