异常
优质
小牛编辑
144浏览
2023-12-01
异常
# 差
fail SomeException, 'message'
# 好
raise SomeException, 'message'
不要在带双参数形式的raise
方法中显式指定RuntimeError
。# 差
raise RuntimeError, 'message'
# 好 - 默认就是 RuntimeError
raise 'message'
倾向使用带异常类、消息的双参数形式调用raise
方法,而不是使用异常的实例。# 差 - 并无 raise SomeException.new('message') [, backtraces] 这种调用形式
raise SomeException.new('message')
# 好 - 与调用形式 raise SomeException [, 'message' [, backtraces]] 保持一致
raise SomeException, 'message'
永远不要从ensure
区块返回。如果你显式地从ensure
区块返回,那么其所在的方法会如同永远不会发生异常般的返回。事实上,异常被默默地丢弃了。def foo
raise
ensure
return 'very bad idea'
end
尽可能隐式地使用begin/rescue/ensure/end
区块。# 差
def foo
begin
# 主逻辑
rescue
# 异常处理逻辑
end
end
# 好
def foo
# 主逻辑
rescue
# 异常处理逻辑
end
通过使用 contingency 方法(一个由 Avdi Grimm 创造的词)来减少begin/rescue/ensure/end
区块的使用。# 差
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
# 差 - 这里将会捕捉 StandardError 及其所有子孙类的异常
read_file rescue handle_error($!)
# 好 - 这里只会捕获 Errno::ENOENT 及其所有子孙类的异常
def foo
read_file
rescue Errno::ENOENT => ex
handle_error(ex)
end
# 差
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
来终止进程。# 差 - 信号与 exit 方法产生的异常会被捕获(除了 kill -9)
begin
exit
rescue Exception
puts "you didn't really want to exit, right?"
# 处理异常
end
# 好 - 没有指定具体异常的 rescue 子句默认捕获 StandardError
begin
# 抛出异常
rescue => e
# 处理异常
end
# 好 - 指定具体异常 StandardError
begin
# 抛出异常
rescue StandardError => e
# 处理异常
end
# 差
begin
# 抛出异常
rescue StandardError => e
# 处理异常
rescue IOError => e
# 处理异常,但事实上永远不会被执行
end
# 好
begin
# 抛出异常
rescue IOError => e
# 处理异常
rescue StandardError => e
# 处理异常
end
f = File.open('testfile')
begin
# .. 文件操作
rescue
# .. 处理异常
ensure
f.close if f
end
# 差 - 需要显式关闭文件描述符
f = File.open('testfile')
# ...
f.close
# 好 - 文件描述符会被自动关闭
File.open('testfile') do |f|
# ...
end