为什么Catch(Exception)几乎总是一个坏主意?

时间:2010-03-10 11:09:49

标签: java exception exception-handling

为什么catch(Exception)几乎总是一个坏主意?

10 个答案:

答案 0 :(得分:55)

因为当您遇到异常时,您应该正确处理。而且您不能指望在代码中处理所有类型的异常。此外,当您捕获所有异常时,您可能会遇到一个异常,该异常无法处理并阻止堆栈中的代码正确处理它。

一般原则是捕捉最具体的类型。

答案 1 :(得分:18)

短篇小说:它被称为bug掩蔽。如果你有一段代码不能正常工作并抛出异常(或者你将错误的输入传递给那段代码)而你只是通过捕获所有可能的异常而使你的眼睛失明,那么你实际上永远不会发现错误并修复它。

答案 2 :(得分:8)

如果能够正确处理异常,您应该只捕获异常。由于你无法正确处理所有可能的异常,你不应该抓住它们: - )

答案 3 :(得分:5)

因为您实际上并不知道发生异常的原因,并且有几个例外需要非常特殊的汽车才能正确处理(如果可能的话),例如OutOfMemoryException和类似的低级系统异常。

因此,您应该只捕获例外:

  • 您确切知道如何处理它(例如FileNotFoundException等)
  • 之后您将重新提升它们(例如执行故障后清理)
  • 何时需要将异常传输到另一个线程

答案 4 :(得分:4)

这取决于你需要什么。如果您需要以不同的方式处理不同类型的异常,那么您应该使用多个catch块并尽可能多地捕获特定的异常。

但有时你可能需要以同样的方式处理所有异常。在这种情况下,catch(Exception)可能没问题。例如:

    try
    {
        DoSomething();
    }
    catch (Exception e)
    {
        LogError(e);
        ShowErrorMessage(e); // Show "unexpected error ocurred" error message for user.
    }

答案 5 :(得分:3)

我发现catch(Exception)的两种可接受用途:

  • 在应用程序的顶层(在返回用户之前)。这样你就可以提供足够的信息。
  • 使用它来掩盖低级异常作为业务异常。

第一种情况是不言自明的,但让我开发第二种情况:

这样做的:

try {
    // xxxx
} catch(Exception e) {
    logger.error("Error XXX",e)
}

是像@dimitarvp那样的bug掩码。

但以下是不同的:

try {
    // xxxx
} catch(Exception e) {
    throw new BussinessException("Error doing operation XXX",e)
}

这样你就不会忽视错误并将它们藏在地毯下面。您正在提供一个高级异常,并向更高的应用程序层提供更具说明性的消息。

在正确的层管理异常也很重要。如果将低级别例外升级到高级业务层,则较高层实际上不可能很好地管理它。

在这种情况下,我更喜欢使用提供更好的上下文和消息的业务来掩盖低级异常,并且还有原始异常以便能够进入细节。

即便如此,如果你能抓住更具体的例外情况并为他们提供更好的治疗,你必须这样做。

如果在代码块中您可以获得SQLExceptionNetworkException,则必须抓住它们并为每个代码提供足够的信息和处理。 但是如果在try / catch块的末尾你有一个Exception映射到BussinessException它对我来说没问题。 事实上,当高级服务层只抛出业务异常(内部细节)时,我发现它已足够了。

答案 6 :(得分:1)

除了@anthares的回答:

  

因为当您遇到异常时,您应该正确处理。而且您不能指望在代码中处理所有类型的异常。此外,当您捕获所有异常时,您可能会遇到一个异常,该异常无法处理并阻止堆栈中的代码正确处理它。

     

一般原则是捕捉最具体的类型。

catch(Exception)是一种不好的做法,因为它也会捕获所有RuntimeException(未经检查的异常)。

答案 7 :(得分:0)

这可能是特定于java的:

有时您需要调用抛出已检查异常的方法。如果这是在您的EJB /业务逻辑层中,您有两个选择 - 捕获它们或重新抛出它们。

捕获特定的异常类意味着当您查看此代码如何处理异常时,您需要重新分析可以引发异常的操作。你会经常进入一个"如果......"如果正确处理异常,可能需要付出很多努力。

重新抛出意味着调用EJB的代码将充斥着捕获代码,这些代码通常对调用类没有任何意义。注:从EJB方法抛出已检查的异常将意味着您负责手动回滚任何事务。

答案 8 :(得分:0)

但有时候还可以!就像你有一段代码可以做一些额外的事情,你真的不关心它,你也不想让它破坏你的应用程序。例如,我最近在一个大型应用程序上工作,我们的业务合作伙伴希望将某个日常事务汇总到新的日志文件中。他们解释说,日志对他们来说并不重要,并且它不符合要求。这只是一些额外的东西,可以帮助他们理解正在处理的数据。他们不需要它,因为他们可以在其他地方获取信息。因此,这是一种罕见的情况,可以很好地捕捉和吞噬异常。

我还在一家捕获所有Throwables的公司工作,然后在自定义的RuntimeException中重新抛出。我不推荐这种方法,只是指出它已经完成了。

答案 9 :(得分:0)

不是另一种有效的方案来确保线程在其中保持活动状态以捕获异常吗?

Thread shouldRunWhenApplicationRuns = new Thread() {
    @Override
    public void run() {
        try {
            // do something that should never end
        } catch (Exception ex) {
            // log it
        }
    };
    shouldRunWhenApplicationRuns.start();