39

有时我会遇到需要捕获异常但从不对其进行任何处理的情况。换句话说,可能会发生异常,但是否发生并不重要。

我最近读了一篇关于类似事情的文章:http ://c2.com/cgi/wiki?EmptyCatchClause

此人谈论如何评论

// should never occur 

是一种代码味道,不应该出现在代码中。然后他们继续解释评论是如何

// don't care if it happens

完全不同,我自己也遇到过这样的情况。例如,在发送电子邮件时,我会执行类似的操作:

var addressCollection = new MailAddressCollection();
foreach (string address in addresses)
{
    try
    {
        addressCollection.Add(address);
    }
    catch (Exception)
    {
        // Do nothing - if an invalid email occurs continue and try to add the rest
    }
}

现在,您可能认为这样做是一个坏主意,因为您希望返回给用户并解释无法将一条或多条消息发送给收件人。但是如果它只是一个抄送地址呢?这不太重要,即使其中一个地址无效(可能只是错字),您仍可能仍想发送消息。

那么我使用空的 catch 块是正确的,还是有更好的选择,我不知道?

4

5 回答 5

92

如果您真的不想在发生某种类型的异常时不做任何事情,那么使用空的 catch 块是完全正确的。您可以通过仅捕获您期望发生并且您知道可以安全忽略的异常类型来改进您的示例。通过捕获Exception,您可以隐藏错误并使自己更难调试程序。

关于异常处理要记住一件事:用于指示程序外部错误条件的异常(至少有时会发生)与指示编程错误的异常之间存在很大差异。第一个示例是异常,表明由于连接超时而无法发送电子邮件,或者由于没有磁盘空间而无法保存文件。第二个例子是一个异常,表明您尝试将错误类型的参数传递给方法,或者您尝试越界访问数组元素。

对于第二个(编程错误),仅仅“吞下”异常将是一个大错误。最好的办法通常是记录堆栈跟踪,然后弹出一条错误消息,告诉用户发生了内部错误,他们应该将日志发送回开发人员(即您)。或者在开发过程中,您可能只是让它在控制台打印堆栈跟踪并使程序崩溃。

对于第一个(外部问题),没有关于“正确”的事情是做什么的规则。这一切都取决于应用程序的细节。如果您想忽略某个条件并继续,那么就这样做。

一般来说:

很高兴您正在阅读技术书籍和文章。你可以从中学到很多东西。但是请记住,当你阅读时,你会发现很多人的建议,说做某事总是错的或总是对的。这些观点常常与宗教接壤。永远不要相信以某种方式做事是绝对“正确的”,因为一本书或文章(或关于 SO...<cough> 的答案)告诉了你。每条规则都有例外,撰写这些文章的人不知道您的应用程序的详细信息。你做。确保您所阅读的内容有意义,如果没有,请相信自己。

于 2013-05-23T13:50:18.917 回答
22

一个空的 catch 块在正确的地方很好- 虽然从你的示例中我会说你绝对应该使用catch (Exception). 相反,您应该捕获您期望发生的显式异常。

这样做的原因是,如果你吞下所有东西,你也会吞下你没有预料到的严重缺陷。“我无法发送到此电子邮件地址”和“您的计算机磁盘空间不足”之间存在天壤之别。如果您的磁盘空间不足,您不想继续尝试发送接下来的 10000 封电子邮件!

“不应该发生”和“不在乎是否发生”之间的区别在于,如果它“不应该发生”,那么当它发生时,你不想默默地吞下它!如果这是您从未预料到的情况,您通常希望您的应用程序崩溃(或至少干净地终止并大量记录发生的事情),以便您可以识别这种不可能的情况。

于 2013-05-23T13:53:13.097 回答
7

如果永远不应该抛出异常,那么捕获它是没有意义的——它永远不应该发生,如果它发生了,你需要知道它。

如果存在可能导致失败的特定场景,那么您应该捕获并测试这些特定场景并在所有其他情况下重新抛出,例如

foreach (string address in addresses)
{
    try
    {
        addressCollection.Add(address);
    }
    catch (EmailNotSentException ex)
    {
        if (IsCausedByMissingCcAddress(ex))
        {
            // Handle this case here e.g. display a warning or just nothing
        }
        else
        {
            throw;
        }
    }
}

请注意,上面的代码捕获特定的(如果是虚构的)异常而不是捕获Exception. 我可以想到很少有合法捕获的情况Exception,而不是捕获您期望抛出的某些特定异常类型。

于 2013-05-23T13:51:25.547 回答
7

许多其他答案给出了很好的理由何时可以捕获异常,但是许多类支持根本不抛出异常的方法。

Try通常这些方法的前面会有前缀。该函数不会抛出异常,而是返回一个布尔值,指示任务是否成功。

一个很好的例子是Parse vs TryParse

string s = "Potato";
int i;
if(int.TryParse(s, out i))
{
    //This code is only executed if "s" was parsed succesfully.
    aCollectionOfInts.Add(i);
}

如果您在循环中尝试上述函数并将其与其 Parse + Catch equilvilant 进行比较,则 TryParse 方法会快得多。

于 2013-05-23T13:58:32.697 回答
2

使用空的 catch 块只会吞下异常,我总是会处理它,即使它向您报告Exception发生了异常。

捕获泛型Exception也是不好的做法,因为它可以隐藏应用程序中的错误。例如,您可能已经捕获了一个ArgumentOutOfRange您没有意识到正在发生的异常,然后将其吞下(即没有对它做任何事情)。

于 2013-05-23T13:50:33.100 回答