在finally块中抛出异常会导致性能问题吗?

时间:2015-07-30 13:50:32

标签: java performance exception exception-handling

在Rational Application Developer(基于eclipse的RAD)中,在软件分析器下,我看到代码审查注释(在Performance => Memory部分下)说"避免最终"内的throw语句。 / p>

在finally块中定义throw会如何影响性能?

enter image description here

这是代码片段,我们已经建议更改代码以记录异常跟踪而不抛出异常,

     } finally {
        if (bufferedReader != null) {
            try {
                bufferedReader.close();
            } catch (final IOException ex) {
                throw ex;
            }
        }
    }

我只是想知道这会如何影响内存和性能?

6 个答案:

答案 0 :(得分:6)

finally块引发的异常将替换从try引发的任何异常,并且可能会丢失有关真实问题的信息。

由于在这种情况下允许try-finally块抛出IOException,所以这是一种更好的编写方法:

try (BufferedReader bufferedReader = Files.newBufferedReader(Paths.get("file.txt"))) {
  /* Work with `bufferedReader` */
}

当块退出时,它会自动关闭阅读器,并且很好地处理任何结果异常,即使try块内的代码首先使用Throwable的“抑制”机制抛出自己的异常。

如果try块无异常地完成,则结果将是关闭资源的结果(异常与否)。如果try块抛出异常,那将是异常结果。但是,如果close()方法也引发异常,它将作为“抑制”异常添加到try块的异常中。您可以以编程方式查询它,并且在打印堆栈跟踪时,将显示被抑制的异常,就像您可能更熟悉的“由...引起的”异常一样。

而且,您可以尝试使用多种资源;这些都将被关闭,并且可以抑制多个闭包异常。

这假设您正在使用文件I / O,但相同的“try-with-resources”结构将适用于实现AutoCloseable(流,SQL对象等)的任何内容。

答案 1 :(得分:3)

这不是性能问题。这是一个正确性问题。 (Marko Topolnik评论警告错误分类似乎对我来说是正确的,我能看到性能角度的唯一方法是,如果try块中抛出的异常被掩盖,那么创建它及其堆栈跟踪所花费的精力就会被浪费掉。但这距离最大的问题还有很长的路要走。)

不在finally块中抛出异常的两个原因:

  • 让finally块抛出异常可以屏蔽try块中抛出的任何异常,因此你会丢失原始的,有用的异常,在日志中不会留下任何实际出错的线索。

  • 当正常的控制流因关闭时抛出异常而中断时,您可能会出现一些短暂的I / O故障(您没有任何控制权,并且不会影响您的业务逻辑) )防止某些有用的工作完成(例如,它可能导致当前事务被回滚)。这可能取决于所涉及的资源类型;也许有些情况下你真的可能想要彻底失败,如果关闭并不干净,但对于很多常见的情况(如JDBC),没有充分的理由去关心。

使用try-with-resources成功排除了异常屏蔽的可能性。但是,如果try逻辑在没有异常的情况下完成,它会让抛出的任何东西得到传播。由于它是一种语言添加,Oracle必须采用最保守的方法,只要注意它在使用时的作用。

答案 2 :(得分:1)

理想的解决方案:

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);
    }
  }
}

答案 3 :(得分:0)

在finally块中,您可以调用另一个传递对象B的方法进行清理。并且您可以尝试使用该方法捕获finally块。

如果你有每个对象的清理方法A& B分别处理try catch finally块。您可以调用两种方法来清理对象。每个对象清理的异常都是独立处理的。

答案 4 :(得分:0)

在给出的代码片段中,没有指向throw语句。 bufferedReader.close()方法已抛出异常。 catch块应该只处理它,而不是抛出另一个异常。事实上,虽然捕获抛出的异常在finally块中肯定是有效的,但我真的不能想到在finally块中抛出异常的正当理由。

至于性能下降,从轶事的角度来看,重新抛出一个被捕获的异常显然不如仅仅处理它有效。

对于一个有害的特定情况,我想起了这样的事情。如果你有另一个方法在finally块中执行清理,例如FileOutputStream.close(),并且第一个方法抛出错误,则第二个方法永远不会运行,因为throw语句结束了块的处理。那时你会泄漏资源。

所以,总而言之,try / catch在finally块中很好,但是为了效率和意外后果(内存泄漏)应该避免使用throw语句。

答案 5 :(得分:-1)

最后用于抛出/捕获异常之后。因此,通过设计,最终不需要抛出异常。这应该只在你的try块中完成。

This可以帮助您了解有关Java中的try-catch-finally异常处理的更多信息