Java 捕获可丢弃项并处理特定异常
好吧,我知道抓一次性的不是个好主意:Java 捕获可丢弃项并处理特定异常,java,exception,exception-handling,Java,Exception,Exception Handling,好吧,我知道抓一次性的不是个好主意: try { // Some code } catch(Throwable e) { // Not cool! // handle the exception } 但最近我正在阅读一段开源代码,我看到了这段有趣的代码(至少对我来说是这样): try { // Some Code } catch (Throwable ex){ response = han
try {
// Some code
} catch(Throwable e) { // Not cool!
// handle the exception
}
但最近我正在阅读一段开源代码,我看到了这段有趣的代码(至少对我来说是这样):
try {
// Some Code
} catch (Throwable ex){
response = handleException(ex, resource);
}
private handleException(Throwable t, String resource) {
if (t instanceof SQLEXception) {
// Some code
} else if (t instanceof IllegalArgumentException) {
//some code
} //so on and so forth
}
这看起来没那么糟吧?这种方法有什么问题?有各种各样的原因说明你不应该抓住一次性的东西。首先,
Throwable
包括Error
s-如果出现其中一个,应用程序通常不会有太多功能。此外,抛弃也减少了你发现发生了什么的机会。你得到的只是“发生了一些不好的事情”——这可能是一场灾难,也可能只是一个麻烦
另一个aproach更好,但当然我仍然不会捕获Throwable,但如果可能的话,尝试捕获更具体的异常。否则你会抓住一切,然后试着找出发生了什么坏事。你的例子可以写成
try {
...
} catch (SQLEXception ex){
response = ... ;
} catch (IllegalArgumentException ex){
response = ...;
}
…这将减少(…instanceof…块)的
数量(这只是因为作者第一次决定在一个大桶中捕获所有内容才需要)。它实际上是抛出可丢弃的
,那么你当然没有太多选择 你说得对,抓捕可丢弃的不是一个好主意。但是,您在问题中提出的代码并不是以一种邪恶的方式捕捉到可丢弃的
,我们稍后再讨论。目前,您在问题中提出的代码有几个优点:
1。可读性
如果仔细查看代码,您会注意到,即使catch块正在捕获一个可丢弃的
,handleException
方法正在检查抛出的异常类型,并可能根据异常类型采取不同的操作
您问题中的代码等同于:
try {
doSomething();
} catch (SQLEXception ex){
response = handleException(resource);
} catch(IllegalArgumentException ex) {
response = handleException(resource);
} catch(Throwable ex) {
response = handleException(resource);
}
即使您只需要捕获10+个异常,此代码也很容易占用大量代码行,而且多捕获结构不会使代码变得更干净。您在问题中呈现的代码只是将catch
委托给另一个方法,以使实际的方法更具可读性
2。可重用性
该方法的代码可以很容易地修改并放置在实用程序类中,并在整个应用程序中访问,以处理异常
s和错误
s。您甚至可以将该方法提取为两个private
方法;一个处理异常
的,一个处理错误
的,并且具有handleException
方法,该方法采用可丢弃
进一步将调用委托给这些方法
3。可维护性
如果您决定要更改应用程序中记录SQLException
s的方式,则必须在单个位置进行此更改,而不是访问引发SQLException
的每个类中的每个方法
那么,捕获可丢弃的是个坏主意吗
您在问题中呈现的代码实际上与单独捕获Throwable
不同。下面的代码是一个很大的禁忌:
try {
doSomething();
} catch(Throwable e) {
//log, rethrow or take some action
}
您应该在catch
链中尽可能远的地方捕获Throwable
或Exception
最后但并非最不重要的一点是,请记住,您在问题中提供的代码是框架的代码,并且框架仍然可以从某些错误中恢复。请参阅以获得更好的解释。因为懒惰而捕获可丢弃的东西是个坏主意。
在引入try multi-catch
之前,这尤其诱人
try {
...
} catch (SomeException e) {
//do something
} catch (OtherException e) {
//do the same thing
} ...
重复catch块既单调又冗长,因此有些人决定只捕获异常
或可丢弃的
,然后处理它。这是应该避免的,因为:
这使得你很难理解你想做什么
你可能会遇到很多你无法处理的事情李>
如果您完全吞下catch block中的可丢弃物品
,则应受到额外惩罚。(我们都见过这样做的代码…:))
但是在绝对必要的时候捕捉可丢弃的是可以的。
什么时候有必要?很少。在框架风格的代码中有各种场景(动态加载外部类是最明显的场景),在独立应用程序中,典型的示例是在退出之前尝试显示/记录某种错误消息。(请记住,尝试可能会失败,因此您不希望将任何关键内容放在那里。)
根据经验,如果您对异常/错误无能为力,您就不应该捕获它。首先,捕获Throwable会使您的应用程序相当不持久。您应该尽可能明确地捕获异常,以便在异常情况下实现良好的可跟踪性
让我们看一看handleException方法(…),看看这种方法会出现的一些问题:
- 您捕获Throwable,但只处理异常,如果抛出类型为Error的OutOfMemoryError,会发生什么情况?-我看到坏事发生了
- 关于使用instanceof进行良好的面向对象编程,它打破了开闭原则,使代码更改(例如添加新的异常)变得非常混乱
在我看来,catch块正是为尝试在handleException(…)中覆盖的功能而设计的,所以请使用它们。Java7解决了一点繁琐的问题,即使用类似的处理多次捕获类似的异常。你绝对不应该做这个人在这里做的事。只要根据需要捕获适当的异常,它可能看起来很难看,但这就是
public static void main(String args[]) {
try {
new Test().test();
} catch (Throwable t) {
t.printStackTrace(System.err);
}
}
try{
//do something that could throw an exception
}catch (ConnectException e) {
//do something related to connection
} catch (InvalidAttributeValueException e) {
// do anything related to invalid attribute exception
} catch (NullPointerException e) {
// do something if a null if obtained
}
catch (Exception e) {
// any other exception that is not handled can be catch here, handle it here
}
finally{
//perform the final operatin like closing the connections etc.
}