在Java中,是否有一种优雅的方法来检测在运行finally块之前是否发生了异常?处理"close()"语句时,通常需要在finally块中进行异常处理.理想情况下,我们希望保留两个异常并将它们传播(因为它们都可能包含有用的信息).我能想到的唯一方法是在try-catch-finally范围之外设置一个变量来保存对抛出异常的引用.然后使用finally块中发生的任何内容传播"已保存"的异常.
有更优雅的方式吗?也许API调用会揭示这个?
这是我正在谈论的一些粗略代码:
Throwable t = null; try { stream.write(buffer); } catch(IOException e) { t = e; //Need to save this exception for finally throw e; } finally { try { stream.close(); //may throw exception } catch(IOException e) { //Is there something better than saving the exception from the exception block? if(t!=null) { //propagate the read exception as the "cause"--not great, but you see what I mean. throw new IOException("Could not close in finally block: " + e.getMessage(),t); } else { throw e; //just pass it up } }//end close }
显然,有许多其他类似的kludges可能涉及将异常保存为成员变量,从方法等返回它...但我正在寻找更优雅的东西.
也许类似Thread.getPendingException()
或类似的东西?就此而言,是否有其他语言的优雅解决方案?
这个问题实际上是从另一个提出一个有趣问题的问题的评论中产生的.
关于在try/catch/finally范围之外设置变量的想法是正确的.
一次传播的异常不能超过一个.
我将存储对Exception对象的引用,而不是使用布尔标志.这样,您不仅可以检查是否发生了异常(如果没有异常,该对象将为null),但如果发生异常,您还可以在finally块中访问异常对象本身.您只需记住在所有catch块中设置错误对象(如果重新抛出错误).
我认为这是一个缺少应该添加的C#语言功能. finally块应该支持对基类Exception类的引用,类似于catch块如何支持它,以便finally块可以使用对传播异常的引用.对于编译器来说,这将是一项简单的任务,为我们节省了手动创建本地Exception变量的工作,并记住在重新抛出错误之前手动设置其值,以及防止我们在设置Exception变量时犯错.不重新抛出错误(记住,它只是我们想要对finally块可见的未捕获的异常).
finally (Exception main_exception) { try { //cleanup that may throw an error (absolutely unpredictably) } catch (Exception err) { //Instead of throwing another error, //just add data to main exception mentioning that an error occurred in the finally block! main_exception.Data.Add( "finally_error", err ); //main exception propagates from finally block normally, with additional data } }
如上所示...我想在finally块中提供异常的原因是,如果我的finally块确实捕获了它自己的异常,那么不要通过抛出新的错误来覆盖主异常(坏)或者只是忽略错误(也是坏的),它可以将错误作为附加数据添加到原始错误中.