我知道这是不好的做法,但我曾经在一个好的程序员写的代码中看到过吞掉异常。所以我想知道这种坏习惯是否有至少一个积极的点。
换句话说,这是不好的,但为什么好的程序员在极少情况下会使用它呢?
try
{
//Some code
}
catch(Exception){}
我知道这是不好的做法,但我曾经在一个好的程序员写的代码中看到过吞掉异常。所以我想知道这种坏习惯是否有至少一个积极的点。
换句话说,这是不好的,但为什么好的程序员在极少情况下会使用它呢?
try
{
//Some code
}
catch(Exception){}
查看我的代码时,我发现在我的日志记录代码中有一个地方,在尝试写入文件和写入事件日志失败后,它会将错误吞噬掉,因为没有其他地方可以报告它。这是其中的一个例子:并没有很多这样的情况。
因为有时候程序员的知识比编译器更丰富。
例如,在某些虚构的语言中,除以0被视为一个错误:
try {
x = 1 / (a*a + 1);
} catch (DivisionByZeroException ex) {
// Cannot happen as a*a+1 is always positive
}
由于一些语言(如Java)要求捕获某些/许多/所有异常,编译器可能会抱怨,而程序员知道这是不可能的。有时,让编译器闭嘴的唯一方法就是明确地吞掉异常。
在编译器不抱怨的语言中,通常根本不会写空的catch语句块。
编辑:实际上,在catch语句块中,我会加入assert(false)。如果理论上不可能发生某些情况,但在实际中确实发生了,那么这是一个非常严重的问题;)
编辑2:Java仅需要捕获已检查的异常。稍微改了一下我的陈述。
throw new AssertionError("This can’t happen", theException);
。 - Ole V.V.我认为一个好的程序员不会这样做而不解释。
try
{
//Some code
}
catch(Exception e) {
// Explanation of why the exception is being swallowed.
}
我很不可能无缘无故地默默吞下 Exception
基类。 我至少会尝试记录错误日志。
这是我今天在项目中偶然遇到的一个具体示例。 这是获取浏览器支持的 XMLHttpRequest
的 JavaScript 函数的一部分。
var XMLHttp = null;
if( window.XMLHttpRequest ) {
try {
XMLHttp = new XMLHttpRequest();
} catch(e) {} // we've already checked that this is safe.
}
else if( window.ActiveXObject ) {
...
}
由于try
被包裹在检查要创建的对象类型的if...else if
中,因此安全地吞咽异常。
catch(e) {throw new AssertionError(e);}
那样处理。实际上,这两种方式没有区别,但是在这里吞掉异常是没有道理的。 - maaartinus我只能想到两种情况,我会忽略异常。
当关闭文件或数据库连接时。如果关闭时出错了,我该怎么办?我想我应该写出一些错误信息,但是如果我已经成功读取了数据,那么它似乎是多余的。而且这似乎是一个非常不可能发生的事件。
在错误处理中更合理:如果我试图写入日志文件失败了,我该在哪里写入错误,以表明我无法写入错误?在某些情况下,您可以尝试写入屏幕,但根据应用程序的不同,这可能是不可能的,例如没有屏幕的后台作业;或者仅仅让用户感到困惑,因为他们无论如何都不能对错误做出任何反应。
另一个帖子提到了一些情况,在这些情况下,您知道异常是不可能的,或者至少,要发生异常,编译器或操作环境必须存在重大问题,例如它没有正确地将两个数字相加,那么谁说异常是有意义的呢?
我完全同意,在这些罕见的情况下,您应该包含一条评论来解释为什么异常是无关紧要的或不可能发生的。但是,我会说,每当您编写潜在具有神秘色彩的代码时,都应该包含解释性评论。
旁注:为什么程序员经常包括像“x = x + 1; //将1添加到x”这样的注释,就像呆子一样,如果没有注释,我永远不会想到,但是又扔进去了没有解释的真正神秘的代码?
在原始帖子四年后的补充说明
当然,即使是好的程序员有时也会忽略异常的真正原因是:“我正在尝试让基本逻辑工作,我不确定如果出现此异常应该怎么办,我现在不想折腾它,我已经花费太多时间在正常的逻辑流程上了,但我以后会回来处理它。” 然后他们忘记了回来处理它。
顺便提一下,有些我认为是相当优秀的程序员表示的一个不好的理由是:"我不想向用户显示晦涩难懂的错误信息,那会让他们感到困惑。最好静默处理这个错误。" 这是一个糟糕的理由,因为:(a)你仍然可以将一些内容写入日志文件;(b)一个晦涩难懂的错误信息真的比让用户误以为操作成功但实际上并没有更糟糕吗?现在客户可能会认为他们的订单正在处理,但实际上并没有,或者他们认为救护车正在派往帮助他们正在痛苦呻吟的孩子,但实际上消息从未传递出去等等。即使在最微不足道的情况下,例如在论坛上发布一条平淡无奇的帖子未能成功,我也宁愿得到一个晦涩的提示信息,至少让我知道发生了什么问题,如果我关心的话我应该再试一次或打电话给某人,而不是说 "更新完成",而实际上并没有更新完成。
有时候即使是优秀的程序员也会犯错。
要么这样,要么你对于一个优秀的程序员的看法与某些人不同(因为一个优秀的程序员会留下一些关于为什么异常被忽略而不是做出一些处理信息的理由)。
是的,我经常在异常清理代码中使用它们,以便不掩盖原始异常。
例如,如果您的catch处理程序尝试回滚事务并在重新抛出异常之前关闭连接,则可能有几个原因导致回滚/关闭本身失败(因为由于原始异常已经处于某些故障状态)。因此,可能需要在try块中包装清理操作,并使用空catch处理程序,基本上表示“如果清理过程中出现问题,那么这有点可以接受,因为我们有更大的问题要报告”。
当无法有效处理异常时,应确保它不会影响应用程序的正常运行,或者它可能代表已知但对整体影响很小的短暂条件。
一个简单的例子是日志记录。你不需要应用程序崩溃仅仅因为某些日志信息不能保存到你的后备存储中。
另一个例子可能是你有替代的处理方式,就像这样:
private Boolean SomeMethod() {
Boolean isSuccessful = false;
try {
// call API function that throws one of several exceptions on failure.
isSuccessful = true;
} catch(Exception) { }
return isSuccessful;
}
我偶然看到了这个旧帖子,并惊讶地发现没有唯一合理的原因,就是为什么好的代码会简单地吞噬异常(无论是否有注释)。
当您使用库和代码时,这些代码位于您控制范围之外,经常会出现需要调用方法以获取可能存在或不存在的某些值,或执行在给定时间点可能不允许的操作的情况。如果您调用的方法在无法返回有效结果时引发异常而不提供控制流替代方案,则必须吞噬异常作为信号表明该值不可用或无法执行该操作。
好的程序员将尽一切努力避免使用异常处理来驱动控制流程,除非出现实际故障场景,这些故障场景很可能冒泡到用户作为错误。然而,好的程序员还广泛地重复使用库和框架以提高效率,并且了解重新编写库以提供更好的替代方案(例如TryGetValue模式)并不总是可行的选项。