【发布时间】:2010-03-10 11:09:49
【问题描述】:
为什么catch(Exception) 几乎总是一个坏主意?
【问题讨论】:
-
你把几乎放进去很好。我无法想象在全局错误处理中不这样做。
标签: java exception exception-handling
为什么catch(Exception) 几乎总是一个坏主意?
【问题讨论】:
标签: java exception exception-handling
因为当您捕获异常时您应该正确处理它。而且你不能期望在你的代码中处理所有类型的异常。此外,当您捕获所有异常时,您可能会得到一个无法处理的异常,并阻止堆栈中的上层代码正确处理它。
一般原则是尽可能捕捉最具体的类型。
【讨论】:
Exception并采取适当的行动。
简短的故事:它被称为错误掩蔽。如果你有一段代码运行不好并抛出异常(或者你向那段代码传递了格式错误的输入),而你只是通过捕获所有可能的异常来蒙蔽你的眼睛,你实际上永远不会发现错误并修复它。
【讨论】:
Exception 是 Java 中所有异常的顶级类。抓住这意味着你抓住了所有可能的错误。你怎么知道在这样的街区做什么?如果您想对某个错误做出反应,请捕获其特定异常并处理它。捕捉所有可能的异常除了让你的眼睛失明之外没有实际用处(我见过很多同事这样做,因为他们想在工作日结束时回家)。
这取决于你需要什么。如果您需要以不同的方式处理不同类型的异常,那么您应该使用多个 catch 块并尽可能多地捕获特定异常。
但有时您可能需要以相同的方式处理所有异常。在这种情况下,catch(Exception) 可能没问题。例如:
try
{
DoSomething();
}
catch (Exception e)
{
LogError(e);
ShowErrorMessage(e); // Show "unexpected error ocurred" error message for user.
}
【讨论】:
我发现catch(Exception) 有两种可接受的用法:
第一个案例是不言自明的,但让我开发第二个:
在做:
try {
// xxxx
} catch(Exception e) {
logger.error("Error XXX",e)
}
就像@dimitarvp 所说的那样屏蔽错误。
但下面不一样:
try {
// xxxx
} catch(Exception e) {
throw new BusinessException("Error doing operation XXX",e)
}
这样您就不会忽略错误并将它们隐藏在地毯下。您正在向更高的应用程序层提供一个带有更多解释性消息的高级异常。
在正确的层管理异常也很重要。如果将低级异常上报到高层业务层,高层几乎不可能很好地管理它。
在这种情况下,我更喜欢使用能够提供更好的上下文和消息并且还具有能够进入细节的原始异常的业务异常来掩盖低级异常。
即便如此,如果你能捕捉到更具体的异常并为它们提供更好的处理,你就必须这样做。
如果在一个代码块中你可以得到一个SQLException 和一个NetworkException,你必须抓住它们并为它们中的每一个提供足够的消息和处理。
但是,如果在 try/catch 块的末尾有一个 Exception 映射到 BusinessException,这对我来说没问题。
事实上,我发现更高的服务层只抛出业务异常(里面有细节)就足够了。
【讨论】:
只有在能够正确处理异常的情况下才应该捕获异常。由于您无法正确处理所有可能的异常,因此不应捕获它们:-)
【讨论】:
java.lang.Error。
除了@anthares 尚未回答的内容:
因为当您捕获异常时您应该正确处理它。而且你不能期望在你的代码中处理所有类型的异常。此外,当您捕获所有异常时,您可能会得到一个无法处理的异常,并阻止堆栈中的上层代码正确处理它。
一般原则是尽可能捕捉最具体的类型。
catch(Exception) 是一种不好的做法,因为它也会捕获所有 RuntimeException(未经检查的异常)。
【讨论】:
因为您并不真正知道为什么会发生异常,并且有几个异常需要非常特殊的汽车才能正确处理(如果可能的话),例如 OutOfMemoryException 和类似的低级系统异常。
因此,您应该只捕获异常:
【讨论】:
OutOfMemoryError 是 Throwable,但属于 java.lang.Error 子类型。所以它不是Exception 并且实际上不会被问题中的子句捕获。也就是说,还有 Exceptions 应该(几乎)永远不会被捕获,例如 NullPointerException,它表示编程错误并且您的积分都是有效的。
这可能是特定于 java 的:
有时您需要调用引发检查异常的方法。如果这是在您的 EJB / 业务逻辑层中,您有 2 个选择 - 捕获它们或重新抛出它们。
捕获特定的异常类意味着当您查看此代码如何处理异常时,您需要重新分析可能引发异常的操作。您经常会陷入“如果……怎么办”的境地,如果异常处理正确,可能需要付出很多努力。
重新抛出意味着调用您的 EJB 的代码将被捕获的代码弄得乱七八糟,而这些代码通常对调用类没有任何意义。注意从 EJB 方法抛出检查异常意味着您有责任手动回滚任何事务。
【讨论】:
但有时还可以!就像你有一段代码做一些“额外”的事情,你真的不关心,你不希望它炸毁你的应用程序。例如,我最近在一个大型应用程序中工作,我们的业务合作伙伴希望将某个日常事务汇总到一个新的日志文件中。他们解释说日志对他们来说并不是那么重要,而且它不符合要求。这只是一些额外的东西,可以帮助他们理解正在处理的数据。他们不需要它,因为他们可以在别处获得信息。所以这是一种罕见的情况,捕捉和吞下异常是完全没问题的。
我还在一家公司工作,该公司捕获了所有 Throwable,然后在自定义 RuntimeException 中重新抛出。我不会推荐这种方法,只是指出它已经完成了。
【讨论】:
确保线程保持活动状态并捕获其中的异常不是另一种有效的方案吗?
Thread shouldRunWhenApplicationRuns = new Thread() {
@Override
public void run() {
try {
// do something that should never end
} catch (Exception ex) {
// log it
}
};
shouldRunWhenApplicationRuns.start();
【讨论】: