在最终阻塞中引发异常是否是性能问题?

在 Rational Application Developer(基于 eclipse 的 RAD)中,在软件分析器下,我看到一个代码审查注释(在 Performance =>Memory 部分下),上面写着“避免 finally 里面的 throw 语句”。

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

enter image description here

这里是代码片段,我们已经建议将代码更改为记录异常跟踪并且不引发异常,

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

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


答案 1

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

由于在这种情况下允许块抛出,因此这里有一个更好的方法来编写它:try-finallyIOException

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

当块退出时,这会自动关闭读取器,并很好地处理任何产生的异常,即使块内的代码首先抛出自己的异常,使用的“抑制”机制。tryThrowable

如果块无一例外地完成,则结果将是关闭资源的结果(异常与否)。如果块引发异常,那将是异常结果。但是,如果该方法也引发了异常,它将作为“抑制”异常添加到块的异常中。您可以通过编程方式对其进行查询,当打印堆栈跟踪时,将显示抑制的异常,就像您可能更熟悉的“由”异常一样。trytryclose()try

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

这假设您使用的是文件 I/O,但相同的“资源试用”结构将适用于实现的任何内容(流、SQL 对象等)。AutoCloseable


答案 2

这不是性能问题。这是一个正确性问题。(Marko Topolnik关于警告被错误分类的评论在我看来似乎是正确的,我能看到性能角度的唯一方法是,如果尝试块中抛出的异常被屏蔽,则创建它所花费的精力及其堆栈跟踪就会被浪费。但这离成为最大的问题还有很长的路要走。

不在最后的块中引发异常的两个原因:

  • 让从 finally 块中引发异常可以掩盖 try 块中引发的任何异常,因此您将丢失原始的有用异常,在日志中不留下任何有关实际出错的线索。

  • 当您的正常控制流因关闭时引发的异常而中断时,您可能会让一些暂时的 I/O 故障(您无法控制这些故障,并且不会影响您的业务逻辑)阻止某些有用的工作完成(例如,它可能会导致当前事务回滚)。这可能取决于涉及何种资源;也许在某些情况下,如果关闭没有干净利落地发生,你真的可能真的想让整个事情失败,但对于很多常见情况(如JDBC),没有充分的理由关心。

使用资源试用成功排除了异常屏蔽的可能性。但是,如果 try 逻辑无异常地完成,则它允许以 close 方式引发的任何内容进行传播。由于它是一种语言的补充,Oracle必须采取最保守的方法,因此当您使用它时,请注意它正在做什么。


推荐