捕获一般异常真的那么糟糕吗?

时间:2008-08-22 07:41:13

标签: exception

在使用FXCop分析一些遗留代码时,我想到在try块中捕获一般异常错误或者您是否正在寻找特定异常真的很糟糕。想看明信片的想法。

15 个答案:

答案 0 :(得分:85)

显然,这是其中一个问题,唯一真正的答案是“它取决于。”

它主要取决于你捕捉异常的地方。一般来说,库在捕获异常时应该更加保守,而在程序的顶层(例如在主方法中或在控制器中的操作方法的顶部等),你可以更自由地捕获你的东西。

原因是例如您不希望捕获库中的所有异常,因为您可能会掩盖与库无关的问题,例如“OutOfMemoryException”,您真的更喜欢冒泡,以便可以通知用户,等等。如果你正在谈论捕获异常的main()方法中的异常,显示它然后退出......好吧,在这里捕获任何异常可能是安全的。

关于捕获所有异常的最重要规则是,您不应该只是静默地吞下所有异常......例如Java中的类似内容:

try { 
    something(); 
} catch (Exception ex) {}

或Python中的这个:

try:
    something()
except:
    pass

因为这些可能是要追查的最难的问题。

一个好的经验法则是,您应该只捕获可以正确处理自己的异常。如果你不能完全处理这个例外,那么你应该让它冒泡给可能的人。

答案 1 :(得分:23)

除非你在应用程序的前端进行一些日志记录和清理代码,否则我认为捕获所有异常是不好的。

我的基本经验法则是捕获您期望的所有异常以及其他任何错误。

如果你抓住所有东西并继续下去,这有点像在你的汽车仪表板上贴上警示灯贴膏药。你不能再看到它,但这并不意味着一切都好。

答案 2 :(得分:15)

是的! (除了申请的“顶部”)

通过捕获异常并允许代码执行继续,您表明您知道如何处理和规避或修复特定问题。您声明这是可恢复的情况。捕获异常或SystemException意味着您将捕获IO错误,网络错误,内存不足错误,缺失代码错误,空指针解除引用等问题。说你可以处理这些是骗人的谎言。

在组织良好的应用程序中,这些不可恢复的问题应该在堆栈中处理。

此外,随着代码的发展,您不希望您的函数捕获将来添加到被调用方法的新异常。

答案 3 :(得分:11)

在我看来,您应该捕获期望的所有例外情况,但此规则适用于除您的界面逻辑之外的任何内容。在调用堆栈中,您应该创建一种捕获所有异常的方法,执行一些日志记录/提供用户反馈,并在需要和可能的情况下正常关闭。

没有什么比一个应用程序崩溃更糟糕了一些用户不友好的堆栈跟踪转储到屏幕上。它不仅会给你的代码提供(也许是不需要的)洞察力,但它也会让你的最终用户感到困惑,有时甚至会把它们吓到竞争对手的应用程序。

答案 4 :(得分:7)

关于这个问题已经进行了很多哲学讨论(更像是争论)。就个人而言,我认为你能做的最糟糕的事情就是吞下异常。接下来最糟糕的是允许一个例外泡沫到表面,用户得到一个令人讨厌的屏幕,充满了技术性的巨型空间。

答案 5 :(得分:3)

好吧,我发现捕获一般异常或特定异常之间没有任何区别,除了当有多个catch块时,你可以根据异常的不同做出不同的反应。

总之,您将使用通用IOException捕获NullPointerExceptionException,但您的程序应该采取的反应方式可能不同。

答案 6 :(得分:3)

我认为这一点是双重的。

首先,如果你不知道发生了什么异常,你怎么能希望从中恢复。如果您希望用户可能输入错误的文件名,那么您可能会遇到FileNotFoundException并告诉用户再试一次。如果相同的代码生成了NullReferenceException并且您只是告诉用户再次尝试,他们就不会知道发生了什么。

其次,FxCop指南专注于图书馆/框架代码 - 并非所有规则都适用于EXE或ASP.Net网站。因此,拥有一个全局异常处理程序可以记录所有异常并很好地退出应用程序是一件好事。

答案 7 :(得分:3)

捕获所有异常的问题在于,您可能正在捕捉您不期望的那些,或者您应该捕获的那些。事实是,任何类型的例外表明出现了问题,您必须在继续之前对其进行排序,否则您可能会遇到数据完整性问题和其他不容易追踪的错误。

举一个例子,在一个项目中我实现了一个名为CriticalException的异常类型。这表示需要开发人员和/或管理人员干预的错误情况,否则客户会收到错误的帐单,或者可能导致其他数据完整性问题。当仅仅记录异常不足时,它也可以用于其他类似的情况,并且需要发送电子邮件警报。

另一个没有正确理解异常概念的开发人员然后包含了一些代码,这些代码可能会在通用try ... catch块中抛出此异常,从而丢弃所有异常。幸运的是,我发现它,但它可能导致严重的问题,特别是因为它应该捕获的“非常罕见”的角落案例比我预期的更常见。

因此,一般情况下,捕获一般异常是不好的,除非您100%确定您知道完全将抛出哪种异常以及在哪种情况下。如果有疑问,请让它们冒泡到顶级异常处理程序。

此处类似的规则永远不会抛出System.Exception类型的异常。您(或其他开发人员)可能希望在调用堆栈的上方捕获您的特定异常,同时让其他人通过。

(但有一点需要注意。在.NET 2.0中,如果一个线程遇到任何未捕获的异常,它会卸载你的整个app域。所以你应该将一个线程的主体包装在一个通用的try ... catch中阻止并将那里捕获的任何异常传递给您的全局异常处理代码。)

答案 8 :(得分:2)

我想玩魔鬼的拥护者来捕获异常并记录它并重新抛出它。例如,如果您在代码中的某个位置发生意外异常,可以捕获它,记录在简单堆栈跟踪中不可用的有意义状态信息,然后将其重新抛出到上层,这是必要的。处理。

答案 9 :(得分:1)

有两种完全不同的用例。第一个是大多数人正在考虑的问题,将try / catch放在一些需要检查异常的操作上。无论如何,这不应该是一个包罗万象。

然而,第二个是阻止程序在可以继续时中断。这些案例是:

  • 所有线程的顶部(默认情况下,异常将消失而无痕迹!)
  • 在您希望永不退出的主要处理循环内
  • 在循环内部处理一个对象列表,其中一个失败不应该阻止其他人
  • “主”线程的顶部 - 您可以在此处控制崩溃,例如在内存不足时将一些数据转储到stdout。
  • 如果您有一个运行代码的“Runner”(例如,如果有人为您添加了一个侦听器并且您调用了侦听器)那么当您运行代码时,您应该捕获Exception以记录问题并让您继续通知其他听众。

这些情况下你总是希望捕获异常(有时甚至可能是Throwable)以捕获编程/意外错误,记录它们并继续。

答案 10 :(得分:0)

我认为一个好的指导方针是只捕获框架内的特定异常(以便主机应用程序可以处理边缘情况,如磁盘填满等),但我不明白为什么我们不应该能够从我们的应用程序代码中捕获所有异常。很简单,有时你不希望应用程序崩溃,无论出现什么问题。

答案 11 :(得分:0)

大部分时间都不需要捕获一般异常。当然,有些情况下你没有选择,但在这种情况下,我认为最好检查一下你需要抓住它的原因。也许你的设计出了问题。

答案 12 :(得分:0)

抓住一般例外情况,我觉得就像在燃烧的建筑物里面拿着一根炸药,然后拿出引信。它有一段时间有所帮助,但是一段时间后炸药就会爆炸。

在corse中,可能存在需要捕获一般异常的情况,但仅用于调试目的。错误和错误应该修复,而不是隐藏。

答案 13 :(得分:0)

对于我的IabManager类(我在应用程序内结算中使用)(来自在线TrivialDrive示例),我注意到有时我会处理很多异常。到了不可预测的地步。

我意识到,只要我停止尝试在一个异常发生后消费应用内产品的尝试,这就是大多数异常发生的地方(在消费中而不是在购买中),安全。

我只是将所有异常更改为一般异常,现在我不必担心会引发任何其他随机的,不可预测的异常。

之前:

    catch (final RemoteException exc)
    {
        exc.printStackTrace();
    }
    catch (final IntentSender.SendIntentException exc)
    {
        exc.printStackTrace();
    }
    catch (final IabHelper.IabAsyncInProgressException exc)
    {
        exc.printStackTrace();
    }
    catch (final NullPointerException exc)
    {
        exc.printStackTrace();
    }
    catch (final IllegalStateException exc)
    {
        exc.printStackTrace();
    }

之后:

    catch (final Exception exc)
    {
        exc.printStackTrace();
    }

答案 14 :(得分:0)

不受欢迎的意见:并非如此。

捕获所有可以有意义地恢复的错误。有时就是全部。

根据我的经验,异常来自何处异常要比实际引发的异常重要得多。如果您将例外情况留在狭窄的地方,那么通常不会吞下任何本来有用的东西。错误类型中编码的大多数信息都是辅助信息,因此,无论如何,您通常最终还是有效地捕获了所有 (但是现在您必须查看API文档以获取可能的例外)。

请记住,几乎在每种情况下,某些异常都应该冒出顶峰,例如Python的KeyboardInterruptSystemExit。幸运的是,对于Python来说,它们被保存在异常层次结构的单独分支中,因此您可以通过捕获Exception来使其冒泡。精心设计的异常层次结构使这种事情真的很简单。

捕获一般异常将导致严重问题的主要时间是在处理需要清理的资源时(也许在finally子句中),因为捕获处理程序很容易错过此类事情。幸运的是,对于使用defer,Python with或C ++和Rust的RAII之类的语言来说,这并不是真正的问题。