在Java中使用Readers和Streams总是让我感到困惑的一件事是该close()
方法可以抛出异常.因为将close方法放在finally块中是个好主意,这需要一些尴尬的情况.我通常使用这种结构:
FileReader fr = new FileReader("SomeFile.txt"); try { try { fr.read(); } finally { fr.close(); } } catch(Exception e) { // Do exception handling }
但我也看到了这种结构:
FileReader fr = new FileReader("SomeFile.txt"); try { fr.read() } catch (Exception e) { // Do exception handling } finally { try { fr.close(); } catch (Exception e) { // Do exception handling } }
我更喜欢第一个结构,因为只有一个挡块,它看起来更优雅.是否有理由更喜欢第二种或替代结构?
更新:如果我指出两者read
并且close
只抛出IOExceptions ,它会有所作为吗?因此,在我看来,如果读取失败,关闭将因同样的原因而失败.
我担心第一个例子存在一个大问题,即如果在读取之后或之后发生异常,则finally
执行该块.到现在为止还挺好.但是,如果fr.close()
然后导致另一个异常被抛出怎么办?这将"胜过"第一个异常(有点像放入return
一个finally
块),你将失去关于实际导致问题开始的所有信息.
你的finally块应该使用:
IOUtil.closeSilently(fr);
这个实用程序方法的作用如下:
public static void closeSilently(Closeable c) { try { c.close(); } catch (Exception e) {} }
我总是会去寻找第一个例子.
如果close是抛出一个异常(在实践中,FileReader永远不会发生),那么标准的处理方式是不是抛出一个适合调用者的异常?近似的例外几乎肯定胜过你使用资源的任何问题.如果你的异常处理的想法是调用System.err.println,第二种方法可能更合适.
存在一个问题,即应该抛出多少异常.应始终重新抛出ThreadDeath,但finally中的任何异常都会阻止它.类似地,Error应该比RuntimeException和RuntimeException更多地抛出异常,而不是检查异常.如果你真的想要,你可以编写代码来遵循这些规则,然后用"执行周期"成语来抽象它.