假设这段代码有20个位置,并且总是相同的
try {
// do something
} catch (FirstException e) {
// log it
} catch (SecondException e) {
// log it
}
使用这样的东西不是更好吗?或者instanceof
不是很好的解决方案?
try {
// do something
} catch(Exception e) {
logException(e);
}
void logException(Exception e) {
if (e instanceof FirstException) {
// log it
} else if (e instanceof SecondException) {
// log it differently
} else {
// do something with other exception
}
}
我唯一讨厌的解决方案是捕获Exception
,这绝对不是最好的方法…有更好的办法吗?
- 在Java 7中,使用
catch (FirstException1 | SecondException | ...)
-
catch (Exception e)
可能没有任何问题;您确实想记录所有异常,不是吗?事实上,我会建议catch (Throwable t)
,因为OutOfMemoryError
s和StackOverflowError
s也想被记录。
从多年记录异常的经验中得出的一个建议是,以相同的方式记录它们。异常消息作为人类可读的文本已经足够了,开发人员调试时真正需要的是堆栈跟踪。
只要注意一件事:永远不要太早捕获异常:在整个应用程序的单个地方捕获它们,即所谓的异常屏障—它位于您进入和退出工作单元的级别。
如果检查异常在较低级别给您带来麻烦,请将它们包装到RuntimeException
:
try {
...
}
catch (RuntimeException e) {throw e;}
catch (Exception e) {throw new RuntimeException(e);}
只有如果您准确地提前知道存在对您的应用程序具有业务级意义的异常,并且将不中止当前工作单元,而是重定向其流,那么在较低级别捕获该异常才是合适的。在实践中,与应用程序代码抛出的所有可能异常的总数相比,这样的异常是很少的。
第一种方法肯定更好。一般来说,捕获Exception
是一个不好的做法,因为在这种情况下,您也捕获了RuntimeException
。
如果您只需要记录异常,则前者是干净且出色的解决方案。
在《重构模式》一书中,常见的重构之一是"用多态性替换instanceof"——换句话说,无论何时使用instanceof,都要考虑多态性是否会更好地工作……
话虽如此,对于这个特殊的问题,我想到了用运行时异常代替受控异常的Spring哲学(请原谅我的双关语)。
这个想法是受控异常可能被过度使用——异常是可以恢复的吗?是,ok…如果没有,就让它沿着链条传播。你可以这样做:
- 重新扔…(但更好)
- 用RuntimeException封装
创建日志Aspect:
另一件要考虑的事情是,如果您确实需要精确地在它们发生的点记录这些异常,而不是让它们在链上传播,和它们发生在20个不同的地方,那么它们是一个横切关注点…您可以使用常规方法重新抛出异常,然后编写一个方面来捕获并记录异常. . . .同样,使用Spring可以简化此操作。