Joh*_*ohn 876 ruby exception-handling
Ryan Davis的Ruby QuickRef说(没有解释):
不要救援Exception.EVER.或者我会刺伤你
为什么不?什么是正确的做法?
And*_*all 1348
TL; DR:StandardError代替一般异常捕获.当重新引发原始异常时(例如,当救援仅记录异常时),救援Exception可能没问题.
Exception是根Ruby的异常层次结构,所以当你rescue Exception从拯救一切,包括子类,如SyntaxError,LoadError和Interrupt.
拯救会Interrupt阻止用户CTRLC退出程序.
抢救SignalException可防止程序正确响应信号.除了之外,它将是不可杀戮的kill -9.
拯救SyntaxError意味着eval失败的s会默默地这样做.
所有这些都可以通过运行此程序来显示,并试图CTRLC或kill它:
loop do
begin
sleep 1
eval "djsakru3924r9eiuorwju3498 += 5u84fior8u8t4ruyf8ihiure"
rescue Exception
puts "I refuse to fail or be stopped!"
end
end
Run Code Online (Sandbox Code Playgroud)
拯救Exception甚至不是默认值.干
begin
# iceberg!
rescue
# lifeboats
end
Run Code Online (Sandbox Code Playgroud)
没有救出Exception,它从中拯救出来StandardError.您通常应该指定比默认值更具体的内容StandardError,但是从Exception 扩大范围而不是缩小范围开始,可能会产生灾难性的结果并使得捕获bug非常困难.
如果您确实需要进行救援,StandardError并且需要具有异常的变量,则可以使用以下形式:
begin
# iceberg!
rescue => e
# lifeboats
end
Run Code Online (Sandbox Code Playgroud)
这相当于:
begin
# iceberg!
rescue StandardError => e
# lifeboats
end
Run Code Online (Sandbox Code Playgroud)
为了挽救Exception日志,为数不多的常见案例之一是用于记录/报告目的,在这种情况下,您应立即重新提出异常:
begin
# iceberg?
rescue Exception => e
# do some logging
raise # not enough lifeboats ;)
end
Run Code Online (Sandbox Code Playgroud)
Mic*_*ade 82
在真正的规则是:不要扔掉异常.你引用的作者的客观性是值得怀疑的,正如它的结尾所证明的那样
或者我会刺伤你
当然,请注意信号(默认情况下)会抛出异常,通常长时间运行的进程会通过信号终止,因此捕获异常而不是终止信号异常将使您的程序很难停止.所以不要这样做:
#! /usr/bin/ruby
while true do
begin
line = STDIN.gets
# heavy processing
rescue Exception => e
puts "caught exception #{e}! ohnoes!"
end
end
Run Code Online (Sandbox Code Playgroud)
不,真的,不要这样做.甚至不要运行它以查看它是否有效.
但是,假设您有一个线程服务器,并且您希望所有例外都不是:
thread.abort_on_exception = true). 那么这在您的连接处理线程中是完全可以接受的:
begin
# do stuff
rescue Exception => e
myLogger.error("uncaught #{e} exception while handling connection: #{e.message}")
myLogger.error("Stack trace: #{backtrace.map {|l| " #{l}\n"}.join}")
end
Run Code Online (Sandbox Code Playgroud)
以上是Ruby的默认异常处理程序的变体,其优点是它也不会杀死你的程序.Rails在其请求处理程序中执行此操作.
主线程中引发了信号异常.后台线程不会得到它们,所以试图在那里捕获它们是没有意义的.
这在生产环境中特别有用,在这种环境中,您不希望程序在出现问题时立即停止.然后,您可以在日志中获取堆栈转储并添加到您的代码中,以便在调用链的更下方以更优雅的方式处理特定异常.
另请注意,还有另一个Ruby习语具有相同的效果:
a = do_something rescue "something else"
Run Code Online (Sandbox Code Playgroud)
在这一行中,如果do_something引发异常,它将被Ruby捕获,被丢弃a并被分配"something else".
一般情况下,不这样做,除非在你特殊的情况下知道你并不需要担心.一个例子:
debugger rescue nil
Run Code Online (Sandbox Code Playgroud)
该debugger函数是在代码中设置断点的一种相当不错的方法,但如果在调试器和Rails之外运行,则会引发异常.从理论上讲,你不应该在你的程序中留下调试代码(pff!没有人这样做!)但你可能会因为某种原因暂时保留它一段时间,但不能继续运行你的调试器.
注意:
如果你运行别人的程序捕获信号异常并忽略它们(比如上面的代码)那么:
pgrep ruby或ps | grep ruby查找违规程序的PID,然后运行kill -9 <PID>. 如果您正在使用其他人的程序,无论出于何种原因,使用这些忽略异常块,那么将其放在主线的顶部就是一个可能的问题:
%W/INT QUIT TERM/.each { |sig| trap sig,"SYSTEM_DEFAULT" }
Run Code Online (Sandbox Code Playgroud)
这导致程序通过立即终止,绕过异常处理程序而不进行清理来响应正常终止信号 .因此它可能导致数据丢失或类似.小心!
如果你需要这样做:
begin
do_something
rescue Exception => e
critical_cleanup
raise
end
Run Code Online (Sandbox Code Playgroud)
你实际上可以这样做:
begin
do_something
ensure
critical_cleanup
end
Run Code Online (Sandbox Code Playgroud)
在第二种情况下,critical cleanup每次都会调用,无论是否抛出异常.
Ben*_*bin 63
假设你在车里(运行Ruby).您最近安装了一个带有无线升级系统(使用eval)的新方向盘,但您不知道其中一个程序员搞砸了语法.
你在桥上,意识到你正朝着栏杆前进,所以你向左转.
def turn_left
self.turn left:
end
Run Code Online (Sandbox Code Playgroud)
哎呀!这可能是不好的,幸运的是,Ruby提出了一个问题SyntaxError.
汽车应立即停止 - 对吧?
不.
begin
#...
eval self.steering_wheel
#...
rescue Exception => e
self.beep
self.log "Caught #{e}.", :warn
self.log "Logged Error - Continuing Process.", :info
end
Run Code Online (Sandbox Code Playgroud)
哔哔
警告:捕获SyntaxError异常.
信息:记录错误 - 继续过程.
您会发现什么是错的,你猛踩紧急中断(^C:Interrupt)
哔哔
警告:捕获中断异常.
信息:记录错误 - 继续过程.
是的 - 这没多大帮助.你离铁轨很近,所以你把车停在公园里(killing :) SignalException.
哔哔
警告:Caught SignalException异常.
信息:记录错误 - 继续过程.
在最后一秒,你拉出钥匙(kill -9),汽车停下来,你向前撞到方向盘(安全气囊不能充气,因为你没有优雅地停止程序 - 你终止了它)和计算机在你的车后面猛烈撞入它前面的座位.半满的可乐可以溢出纸张.背面的杂货被粉碎,大部分都是蛋黄和牛奶.汽车需要严格的维修和清洁.(数据丢失)
希望你有保险(备份).哦是的 - 因为安全气囊没有膨胀,你可能会受伤(被解雇等).
可是等等!有更多你可能想要使用的原因rescue Exception => e!
假设你是那辆车,如果汽车超过其安全停止动力,你想确保安全气囊膨胀.
begin
# do driving stuff
rescue Exception => e
self.airbags.inflate if self.exceeding_safe_stopping_momentum?
raise
end
Run Code Online (Sandbox Code Playgroud)
以下是规则的例外情况:Exception 只有在重新引发异常时才能捕获.因此,更好的规则是永不吞咽Exception,并始终重新提出错误.
但是在像Ruby这样的语言中添加救援很容易被遗忘,并且在重新提出问题之前立即发布救援声明感觉有点不干.而你不想要忘记的raise声明.如果你这样做,祝你好运,找到那个错误.
值得庆幸的是,Ruby非常棒,你可以使用ensure关键字来确保代码运行.该ensure关键字将不管运行代码-如果一个异常被抛出,如果不是,唯一的例外是,如果世界结束(或其他不可能事件).
begin
# do driving stuff
ensure
self.airbags.inflate if self.exceeding_safe_stopping_momentum?
end
Run Code Online (Sandbox Code Playgroud)
繁荣!并且该代码应该运行.您应该使用的唯一原因rescue Exception => e是您需要访问异常,或者您只希望代码在异常上运行.并记得重新提出错误.每次.
注意:正如@Niall指出的那样,确保始终运行.这很好,因为有时你的程序会骗你,而不会抛出异常,即使出现问题.对于像气囊充气这样的关键任务,无论如何都要确保它发生.因此,每次停车检查是否抛出异常都是一个好主意.尽管在大多数编程环境中充气安全气囊是一项不常见的任务,但实际上这对于大多数清理任务来说都很常见.
不要rescue Exception => e(而不是重新提出异常) - 或者你可能会开出一座桥.
Ser*_*sev 46
因为这会捕获所有异常.您的程序不可能从任何程序中恢复.
您应该只处理您知道如何从中恢复的异常.如果您没有预料到某种异常,请不要处理它,大声崩溃(将详细信息写入日志),然后诊断日志并修复代码.
吞咽异常是不好的,不要这样做.
小智 15
这篇博文完美地解释了这一点: Ruby's Exception vs StandardError: What’s the Difference?
为什么你不应该拯救异常
拯救Exception的问题在于它实际上拯救了从Exception继承的每个异常。这是……全部!
这是一个问题,因为 Ruby 内部使用了一些异常。它们与您的应用程序没有任何关系,吞下它们会导致不好的事情发生。
以下是一些重要的:
SignalException::Interrupt - 如果您挽救此问题,则无法通过按 control-c 退出应用程序。
ScriptError::SyntaxError - 吞咽语法错误意味着像 put("Forgot Something) 这样的事情会默默地失败。
NoMemoryError - 想知道当你的程序用完所有 RAM 后继续运行时会发生什么?我也不。
Run Code Online (Sandbox Code Playgroud)begin do_something() rescue Exception => e # Don't do this. This will swallow every single exception. Nothing gets past it. end我猜你并不想接受任何这些系统级异常。您只想捕获所有应用程序级别的错误。异常导致了您的代码。
幸运的是,有一个简单的方法可以做到这一点。
改为拯救 StandardError
您应该关心的所有异常都继承自 StandardError。这些是我们的老朋友:
NoMethodError - 当您尝试调用不存在的方法时引发
TypeError - 由 1 + "" 等原因引起
RuntimeError - 谁会忘记古老的 RuntimeError?
要挽救此类错误,您需要挽救 StandardError。你可以通过写这样的东西来做到这一点:
Run Code Online (Sandbox Code Playgroud)begin do_something() rescue StandardError => e # Only your app's exceptions are swallowed. Things like SyntaxErrror are left alone. end但 Ruby 让它更容易使用。
当您根本不指定异常类时,Ruby 会假定您指的是 StandardError。所以下面的代码与上面的代码是相同的:
Run Code Online (Sandbox Code Playgroud)begin do_something() rescue => e # This is the same as rescuing StandardError end
| 归档时间: |
|
| 查看次数: |
278039 次 |
| 最近记录: |