[英]Is throwing an exception inside a finally block a performance issue?
在Rational Application Developer(基于eclipse的RAD)中,在软件分析器下,我看到了一个代码审查注释(在Performance => Memory部分下),说“避免最终的throw语句”。
如何在finally块中定义throw会影响性能?
这是代码片段,我们已经建议更改代码以记录异常跟踪并且不抛出异常,
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (final IOException ex) {
throw ex;
}
}
}
我只是想知道这会如何影响内存和性能?
从finally
块抛出的异常将替换从try
中抛出的任何异常,并且有关真正问题的信息可能会丢失。
由于在这种情况下允许try-finally
块抛出IOException
,这是一个更好的编写方式:
try (BufferedReader bufferedReader = Files.newBufferedReader(Paths.get("file.txt"))) {
/* Work with `bufferedReader` */
}
这会在块退出时自动关闭阅读器,并且很好地处理任何结果异常,即使try
块内的代码首先使用Throwable
的“suppress”机制抛出自己的异常。
如果try
块无异常地完成,则结果将是关闭资源的结果(异常与否)。 如果try
块抛出异常,那将是异常结果。 但是如果close()
方法也引发异常,它将作为“抑制”异常添加到try
块的异常中。 您可以以编程方式查询它,并且在打印堆栈跟踪时,将显示被抑制的异常,就像您可能更熟悉的“由...引起的”异常一样。
并且,您可以尝试使用多种资源; 这些都将被关闭,并且可以抑制多个闭包异常。
这假设您正在使用文件I / O,但相同的“try-with-resources”结构将适用于实现AutoCloseable
(流,SQL对象等)的任何内容。
这不是性能问题。 这是一个正确性问题。 (Marko Topolnik评论警告错误分类似乎对我来说是正确的,我能看到性能角度的唯一方法是,如果try块中抛出的异常被掩盖,那么创建它及其堆栈跟踪所花费的精力就会被浪费掉。但这距离最大的问题还有很长的路要走。)
不在finally块中抛出异常的两个原因:
让finally块抛出异常可以屏蔽try块中抛出的任何异常,这样就会丢失原始的,有用的异常,在日志中不会留下实际出错的线索。
如果正常的控制流因为关闭时抛出的异常而中断,您可能会让一些短暂的I / O故障(您没有任何控制权,哪些不影响您的业务逻辑)会阻止某些有用的操作从完成工作(例如,它可能导致当前事务回滚)。 这可能取决于所涉及的资源类型; 也许有些情况下你真的可能想要失败整个事情,如果关闭没有干净地发生,但对于很多常见的情况(如JDBC),没有充分的理由去关心。
使用try-with-resources成功排除了异常屏蔽的可能性。 但是,如果try逻辑在没有异常的情况下完成,它会让抛出的任何东西得到传播。 由于它是一种语言添加,Oracle必须采取最保守的方法,只需要知道它在使用它时正在做什么。
理想解决方案
try (BufferedReader bufferedReader = ...) {
//do stuff
}
但也许你在java 1.6中:
BufferedReader bufferedReader = null;
try{
bufferedReader = ...;
//do stuff
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (final IOException ex) {
logger.error("Problem while cleaning up.", ex);
}
}
}
在finally块中,您可以调用另一个传递对象B的方法来进行清理。 你可以尝试在该方法中捕获finally块。
如果你有单独的每个对象A和B的清理方法,你可以处理try catch finally块,这很好。 您可以调用两种方法来清理对象。 每个对象清理的异常都是独立处理的。
在给出的代码片段中,没有指向throw语句。 bufferedReader.close()方法已抛出异常。 catch块应该只处理它,而不是抛出另一个异常。 实际上,虽然捕获抛出的异常在finally块中肯定是有效的,但我真的不能想到在finally块中抛出异常的正当理由。
至于性能下降,从轶事的角度来看,重新抛出一个被捕获的异常显然不如仅仅处理它有效。
至于一个特定的例子,这将是有害的,这样的事情让我想起了我的头脑。 如果你有另一个方法在finally块中执行清理,例如FileOutputStream.close(),并且第一个方法抛出错误,则第二个方法永远不会运行,因为throw语句结束了块的处理。 那时你会泄漏资源。
总而言之,try / catch在finally块中很好,但是为了效率和意外后果(内存泄漏)应该避免使用throw语句。
最后用于抛出/捕获异常之后。 因此,通过设计,最终不需要抛出异常。 这应该只在你的try块中完成。
这可能有助于您了解有关Java中try-catch-finally异常处理的更多信息
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.