我有时会抛弃异常吗?

时间:2010-01-26 19:56:39

标签: exception exception-handling

我有一个最佳实践问题。我意识到这是主观的,但是如果这是一种常见的编程习惯,我想问一下比我聪明的人。

如果你有一种非常重要的方法,你不想干扰应用程序的重要功能,那么使用像这样的错误接收器是否常见?

Try 
    'do stuff.  not important if it fails.

Catch ex as exception
    'sink.  do nothing.
End Try

如果您正在考虑雇用我而且您正在阅读我的一些代码,并且看到了这个......你会吗?

赛斯

修改 哇!谢谢你的回答。我认为共识是永远不应该做的,或者它应该是非常罕见的。

我想我会给你这个问题的背景。首先,我非常熟悉Karl Sequin的文章,并且已经遵循了这种模式多年。

但是今天在我正在进行的项目中,我正在完成更改列表,并面临着添加一个简单的功能。 (如果您想知道......它正在为富文本框添加上下文菜单支持。)

随附的说明说,“如果花费的时间超过15分钟......就放下它。”

所以我面临着添加一个潜在有用的功能但是没有时间来测试它不会破坏工作功能。对于记录,我们的此系统的异常处理程序具有处理和下沉或记录这些错误的机制。但是如果我正在开发一个没有强大错误处理系统的系统呢?是否可以添加此功能,如果发生错误......什么都不会丢失。

这是我的想法。但我已经把你的信息铭记于心......基本上这是一个坏主意。

赛斯

21 个答案:

答案 0 :(得分:13)

是的,这很常见,但一般情况下不应该这样做。

有一些例外情况,例如OutOfMemoryException,除非你抓住他们尝试优雅地终止你的应用程序,否则最好不要抓住它们。

在大多数情况下,吞咽System.ExceptionSystem.SystemException将不可避免地隐藏进一步的运行时问题。

答案 1 :(得分:8)

您应该永远隐藏例外。无论如何我可能会雇用你,但是当你为我工作时你不会这样做:)

但是,严肃地说,在Java(例如)中,例外用于您可能选择忽略的某些情况,例如FileNotFoundException(就像您所做的那样,带有注释)。但是如果你遇到过一种类型的异常 - 比如IOException - 你不能只是隐藏它。如果Exception对您没有任何意义,请将其包装在RuntimeException中并将其抛给客户端。

在此过程中,应该处理Exception,但不要隐藏。

答案 2 :(得分:7)

这很常见,但最好避免它。至少你应该在某处记录异常。

另外,避免使用流控制的异常。应编写您的代码以处理所有可能的情况,而无需诉诸异常。除了性能提升之外,此方法还告诉您,当异常发生时,值得您注意。

答案 3 :(得分:5)

你不应该在这里捕捉所有例外。在极少数情况下,可以忽略特定的预期异常。但是,抓住所有例外并吞下它们将意味着您尝试在OutOfMemoryException和其他不可恢复的例外后继续

答案 4 :(得分:5)

虽然这里的大多数人实际上是在谈论开发者,但我想指出 从故事的另一个观点来看。

我承认:我已经吞下了异常,并且在每种情况下都是因为恕我直言的设计师 功能搞砸了

“例外”表示“例外”,而不是失败或错误。我的意思是:如果功能 必须承认输入可能不正确,我希望功能确实如此 不要使用例外。我的愤怒特别针对“ParseException”。

如果你解析输入,你很可能会发现未知/损坏/不精确的输入。那 是“正常的”,也不例外。在这种情况下,如果开发人员,我觉得很烦人 如果函数无法正确解析,函数抛出ParseException。

为什么?

  • 例外打破了控制流程
  • 异常缓慢
  • 无论如何通常无关紧要,因为您正在使用默认值进行初始化。

如果您将数千或数百万(!)次调用parseFunction,则会严重阻塞日志文件中的

相反,我的理想函数返回一个带有状态代码和的类对象 消息如

StatCode stat = parseXYZ(Reader r);

然后可以进行测试。

if (stat.code != OK)  
  //whatever

如果在另一方面,您遇到了无法预见的问题(文件未锁定, 无意义的论证,非法的线程状态)异常非常好。

答案 5 :(得分:4)

最佳做法是说你不应该这样做。什么是不重要的,你不想知道发生了错误?我不认为我曾经遇到过这个。

我要么不使用try catch结构,要么将代码重构为返回布尔值的方法,这样我至少可以识别它是否成功...

这是我的想法......

更新:有时您可能需要接收异常。在这些情况下,我会确定哪些异常可能是此候选,然后捕获这些特定异常。但这远不是捕捉Exception,这可能是任何事情,例如前面提到的OutOfMemoryException。简而言之,我只会抓住特定的例外,意图忽略它。

答案 6 :(得分:4)

我个人认为这是一种非常糟糕的做法。

这是(不幸的是)在查看代码时我一直在寻找的东西之一,当我找到空的catch块或捕获基本上吞下异常的块时我问的问题是:

  1. 此时您是否100%确定此例外情况永远不会重要?
  2. 您是否100%确定将来发现的任何异常都无关紧要,无论代码库如何发展?
  3. 即使1和2都是真的,在这里放一些记录真的很难吗?
  4. 对我来说最重要的是日志记录 - 良好的异常记录以及良好的程序执行跟踪是设计可以随着时间的推移安全修改的代码的基础,并且演变成一个用户信赖的稳定系统英寸

    除此之外,一个好的做法是只捕获特定的异常,并让所有其他异常在堆栈中冒泡。盲目处理异常作为处理错误的方法永远不正确。

答案 7 :(得分:1)

一般来说,我认为这是不好的做法 - 但是让我们说有问题的方法是一种记录方法。我不希望我的应用程序崩溃,因为EventLog已满。在这种情况下,我会说没关系。我仍然会将它输出到Debug窗口。

答案 8 :(得分:1)

我认为回答这个问题的最佳方法是讨论可以接受的情况。 在大多数情况下,它不安全。在安全的情况下,通常最好至少在警告,调试或跟踪日志中吐出一些有关它的信息。我只能想到一些安全的案例:

您期望一个非常具体的异常,并且知道您可以从中恢复:

try {
 Integer.Parse(someString);
}
catch (ParseException pe) {
 //In this particular use case, if the string doesn't parse, 
 //I don't need to do anything. Logging a warning might be a
 //good idea, in some cases
}

您正在使清理代码安全:

beginDatabaseTransaction();
try {
 doSomeDatabaseOperation();
}
catch (Exception e) {
 log.error(e); //log the original exception
 try {
  rollbackDatabaseConnection();
 }
 catch(Exception e2) {
  //You may ignore this one-off exception, though
  //I would strongly consider logging it
 }
 throw; //rethrow the original exception and let it propagate
}

(这绝不是数据库操作的最佳实践模式;只是一个人为的例子。)

在我们的生产系统中,我们遇到过多个案例,其中过度热心的异常陷阱造成的损害远远超过它的好处。小心这个。

另一件事:如果除了要抛出的特定错误之外没有其他东西,通常不应该试图抓住它。

大多数例外都可以帮助您,开发人员找到并诊断代码中的错误。它们旨在使程序(或当前操作)终止,以防止不可预测的行为(如尝试加载数据库中的所有记录,因为您无法为SQL语句构造WHERE子句。)当您捕获到未知异常时,您将隐藏当前正在运行的代码中的错误,并使代码可能出现意外行为,而不仅仅是终止。

答案 9 :(得分:1)

作为一名负责修复错误的新手,我发现我分配的特定错误是打印(调试)“这应该永远不会发生。”在克服了我在一个显然不可能的错误状态下工作的恐惧之后,我终于设法发现它是由一种微妙的竞争条件引起的。如果该代码的作者最初只是在没有至少那么微小的调试语句的情况下陷入异常,那么追踪竞争条件会更加困难。

从那以后,我成为了处理异常或推广异常的巨大支持者,直到以最友好的方式向最终用户显示错误条件,这是简单地记录调试语句的一步。

答案 10 :(得分:1)

有时我发现开发人员宁愿捕获并吞下异常而不是编写正确的错误处理代码。

有一些代码,如果抛出异常,它们会捕获异常,尝试别的东西,如果抛出异常,则执行其他操作等。异常是对象,并在抛出时创建。如果可以,请编写正确的处理代码来处理错误,并且只在can't continue出于任何原因使用例外。

至于吞咽异常,如果我说我编写的代码没有,我会撒谎。这不是最佳实践,更不用说在程序运行不佳时非常难以调试。我也被他们咬过了。

答案 11 :(得分:1)

您应该区分可忽略例外和致命例外。我不确定这是如何在VB中完成的,但在Java中(例如),从Error派生的异常应该永远被忽略。这包括类加载器失败,内存不足,堆栈溢出等等。

答案 12 :(得分:1)

这几乎不是一个好主意,但取决于你如何做例外,有些情况适用。例如:

try {
   Cache.refresh(myObject)
}
catch (NotInCacheException) {
   // If the object isn't already in the cache, then we don't have to worry 
   // about refreshing it. It's assumed that this is a common occurrence,
   // so we don't need to log it either; that ends up just spamming
   // the logs. So, just swallow it, silently.
}

(注意:Cache.refresh()是否应该抛出一个NotInCacheException在这里没有问题;我只是用它作为一个简单的例子。)

但请注意:如果您有一个非常具体的异常,那么您只能逃避这一点。在您的示例中,您正在捕捉Exception,这是方式太高级别(您将吞下其他人提到的严重错误)。

另外:如果您有一个灵活的日志记录框架,您可能希望记录此异常,以供参考。我在这里特别考虑Log4Net / Log4J:您可以配置日志记录(甚至在运行时),根据类和严重性选择/忽略异常。因此,您可以在正常情况下使这些类型的异常静音,但如果您想在应用程序中进行一些操作,请记录它们。

如果您决定吞下该例外,我的政策是始终有一个代码注释,解释您为何这样做;这标志着它不仅仅是另一种糟糕的开发实践。

答案 13 :(得分:1)

Best Practices for Handling Exceptions (MSDN)

据他们说,你可以

  

对错误做点什么或忽略它。

由你和你的团队来决定我猜。

答案 14 :(得分:1)

不,我觉得这不行。

您的系统可能并不重要,但可能您确实希望它能够运行,否则您不会首先编写它。现在,如果有一天它停止运行,那些必须维护它的人不知道为什么它突然不起作用,因为你完全隐藏了错误。事实上,甚至可能需要很长时间才能意识到错误的来源,或者甚至首先出现错误。它可能会浪费大量的开发人员时间,而记录错误而不是丢弃错误并不会花费太多时间。

你正在捕捉像OutOfMemoryException这样的异常,你真的不想捕捉和丢弃。如果该代码非关键但占用的内存太多并且使整个系统变慢,那么您希望被告知,以便您可以修复它。

答案 15 :(得分:0)

我只是在关闭连接等烦人的例外时这样做:

try {
   conn.close()
}
catch( Exception e ) {
}

因为我已经确定我不再需要它了。

答案 16 :(得分:0)

我认为你可以做到,但你必须睁大眼睛,知道你为什么这么做。仔细考虑一下。在我的商店,我们要求您发表评论,说明您为什么要吃异常

答案 17 :(得分:0)

如果这是一件好事,取决于语言和例外情况有多昂贵。你仍然不应该捕获所有异常,但是,例如,在Python中,以下是一个常见的习语:

d={}
for i in theList:
  try:
    d[i] += 1
  except KeyError:
    d[1] = 1

这是进行默认插入的最快方法。您对DivisionByZeroError或任何其他异常执行相同的操作。一堆流控制结构的定义归结为raise StopIteration

答案 18 :(得分:0)

。如果使用vs2008,您至少可以将它们发送到调试窗口

 System.Diagnostics.Debug.WriteLine("exception in method - my method -: "+ex.message);

答案 19 :(得分:0)

Java突出了使用Exceptions进行编程的必要性。我发现Java倾向于自愿抛出异常,这很烦人,因为如果你不希望你的应用程序崩溃,你必须抓住它们。不幸的是,Java中的异常是一个相当重要的功能。

我学会了有效地使用Icon中的异常。 Icon有这个简洁的东西叫做'失败'。如果表达式没有可以返回的值,它将改为失败。这只是一个微型例外而不是try {} catch {}表示法,失败由语言元素直接处理,例如ifwhile

IMO,这就是Exceptions应该如何在Java中运行......但不幸的是,它们没有。相反,您最终会编写防御性代码以防止异常,而不是轻松自然地处理它们。默默地吞下一个特殊的例外,因为它比预防它更加罕见和优雅,我认为这是一个有用的伎俩。但是,这是响应“你必须先知道规则才能打破它们”的事情。换句话说,不要经常这样做。

我希望更多语言支持Icon中的成功/失败模型。

答案 20 :(得分:0)

我会说“不要这样做” - 不是那样的。

首先,尝试重构“非关键”代码,这样就不会抛出异常。

如果你不能这样做,至少不要盲目地抓住 Exception。只捕获你期望它抛出的异常(并将它们记录到某处!) - 其他任何 你需要知道的东西。