• 不要在带双参数形式的 raise 方法中显式指定 RuntimeError
    [link]

    1. # 差
    2. raise RuntimeError, 'message'
    3. # 好 - 默认就是 RuntimeError
    4. raise 'message'

  • 倾向使用带异常类、消息的双参数形式调用 raise 方法,而不是使用异常的实例。
    [link]

    1. # 差 - 并无 raise SomeException.new('message') [, backtraces] 这种调用形式
    2. raise SomeException.new('message')
    3. # 好 - 与调用形式 raise SomeException [, 'message' [, backtraces]] 保持一致
    4. raise SomeException, 'message'

  • 永远不要从 ensure 区块返回。如果你显式地从 ensure 区块返回,那么其所在的方法会如同永远不会发生异常般的返回。事实上,异常被默默地丢弃了。
    [link]

    1. def foo
    2. raise
    3. ensure
    4. return 'very bad idea'
    5. end

  • 通过使用 contingency 方法(一个由 Avdi Grimm 创造的词)来减少 begin/rescue/ensure/end 区块的使用。
    [link]

    1. # 差
    2. begin
    3. something_that_might_fail
    4. rescue IOError
    5. # 处理 IOError
    6. end
    7. begin
    8. something_else_that_might_fail
    9. rescue IOError
    10. # 处理 IOError
    11. end
    12. # 好
    13. yield
    14. rescue IOError
    15. end
    16. with_io_error_handling { something_that_might_fail }
    17. with_io_error_handling { something_else_that_might_fail }

  • 不要抑制异常。
    [link]

    1. # 差
    2. begin
    3. # 抛出异常
    4. rescue SomeError
    5. # 不做任何相关处理
    6. end
    7. # 差
    8. do_something rescue nil

  • 避免使用 rescue 修饰语法。
    [link]

    1. # 差 - 这里将会捕捉 StandardError 及其所有子孙类的异常
    2. read_file rescue handle_error($!)
    3. # 好 - 这里只会捕获 Errno::ENOENT 及其所有子孙类的异常
    4. def foo
    5. read_file
    6. rescue Errno::ENOENT => ex
    7. handle_error(ex)
    8. end

  • 避免捕获 Exception。这种做法会同时将信号与 exit 方法困住,导致你必须使用 kill -9 来终止进程。
    [link]

    1. # 差 - 信号与 exit 方法产生的异常会被捕获(除了 kill -9)
    2. begin
    3. exit
    4. rescue Exception
    5. puts "you didn't really want to exit, right?"
    6. # 处理异常
    7. end
    8. # 好 - 没有指定具体异常的 rescue 子句默认捕获 StandardError
    9. begin
    10. rescue => e
    11. # 处理异常
    12. end
    13. # 好 - 指定具体异常 StandardError
    14. begin
    15. # 抛出异常
    16. rescue StandardError => e
    17. # 处理异常
    18. end

  • 把较具体的异常放在处理链的较上层,不然它们永远不会被执行。
    [link]

    1. # 差
    2. begin
    3. # 抛出异常
    4. rescue StandardError => e
    5. # 处理异常
    6. rescue IOError => e
    7. # 处理异常,但事实上永远不会被执行
    8. end
    9. # 好
    10. begin
    11. # 抛出异常
    12. rescue IOError => e
    13. # 处理异常
    14. rescue StandardError => e
    15. # 处理异常
    16. end

  • ensure 区块释放程序的外部资源。
    [link]

    1. f = File.open('testfile')
    2. begin
    3. # .. 文件操作
    4. rescue
    5. # .. 处理异常
    6. ensure
    7. end

  • 倾向使用标准库中的异常类而不是引入新的类型。
    [link]