Java io ugly try-finally block
有没有那么丑陋的方式来处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | InputStream in = new FileInputStream(inputFileName); OutputStream out = new FileOutputStream(outputFileName); try { copy(in, out); } finally { try { in.close(); } catch (Exception e) { try { // event if in.close fails, need to close the out out.close(); } catch (Exception e2) {} throw e; // and throw the 'in' exception } } out.close(); } |
更新:以上所有代码都在一个try-catch中,感谢您的警告。
最后(答案之后):
而且,可以使用Execute Around惯用语来完成一个好的实用程序方法(感谢Tom Hawtin)。
这是正确的idom(并且工作正常):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | InputStream in = null; OutputStream out = null; try { in = new FileInputStream(inputFileName); out = new FileOutputStream(outputFileName); copy(in, out); finally { close(in); close(out); } public static void close(Closeable c) { if (c == null) return; try { c.close(); } catch (IOException e) { //log the exception } } |
之所以能正常工作,是因为只要您的finally代码本身不会引发异常或以其他方式异常终止,那么在您最终到达之前抛出的异常将在您的finally代码完成之后引发。
编辑:从Java 7(和Android SDK 19-KitKat)开始,现在有了Try with resources语法以使此方法更简洁。这个问题解决了如何处理。
您可以实现一个实用程序方法:
1 2 3 4 5 6 7 8 9 10 11 | public final class IOUtil { private IOUtil() {} public static void closeQuietly(Closeable... closeables) { for (Closeable c : closeables) { if (c != null) try { c.close(); } catch(Exception ex) {} } } } |
然后,您的代码将简化为:
1 2 3 4 5 | try { copy(in, out); } finally { IOUtil.closeQuietly(in, out); } |
额外
我想在第三方开源库中会有这样的方法。但是,我的首选是避免不必要的库依赖关系,除非我使用了大部分功能。因此,我本人倾向于实现简单的实用程序方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | try { final InputStream in = new FileInputStream(inputFileName); try { final OutputStream out = new FileOutputStream(outputFileName); try { copy(in, out); out.flush(); // Doesn't actually do anything in this specific case. } finally { out.close(); } } finally { in.close(); } } catch (IOException exc) { throw new SomeRelevantException(exc); } |
请记住,打开流可能会引发异常,因此在流开口之间确实需要
事实证明,
从Java SE 7开始,您可以编写使用try-with-resource来避免太多缩进。尽管隐藏了隐藏的异常,但它或多或少地做同样的事情。
1 2 3 4 5 6 7 8 9 | try ( final InputStream in = new FileInputStream(inputFileName); final OutputStream out = new FileOutputStream(outputFileName); ) { copy(in, out); out.flush(); // Doesn't actually do anything in this specific case. } catch (IOException exc) { throw new SomeRelevantException(exc); } |
您可能要使用Execute Around惯用语。
我相信复制的标准好方法是使用NIO的
Guava具有非常好的IO API,因此无需这样做。例如,您的示例将是:
更一般而言,它使用
此外,它具有
其中的IO内容仍处于测试阶段,并且可能会发生变化,但是值得一试甚至使用,具体取决于您正在处理的内容。
从Java 7开始,有一种更好的方式来编写关于
现在,您可以在
1 2 3 | try (initialize resources here) { ... } |
代码块完成后,它们将自动关闭。 不需要
一个例子:
1 2 3 4 5 6 7 8 9 10 11 12 | try ( ZipFile zf = new ZipFile(zipFileName); BufferedWriter writer = Files.newBufferedWriter(outputFilePath, charset); ) { // Enumerate each entry for (Enumeration entries = zf.entries(); entries.hasMoreElements();) { // Get the entry name and write it to the output file String newLine = System.getProperty("line.separator"); String zipEntryName = ((java.util.zip.ZipEntry)entries.nextElement()).getName() + newLine; writer.write(zipEntryName, 0, zipEntryName.length()); } } |
在
我坚信,在Java 7.0中,您不再需要自己显式关闭流。 Java 7中的语言功能
1 2 3 |
在IOUtils中,您共有一些closeQuietly方法。
我有时使用的一个技巧是定义一个名为
Java 7可能会改善情况。据报道,它将拥有一个新的结构,该结构提供了一种更为简洁的方式来管理托管资源。例如完成时需要关闭的流。
最后,您应该意识到您的示例存在错误。如果该方法调用打开第二个流,则第一个流将不会关闭。第二次打开需要在
在大多数情况下," in" close()异常是无关紧要的,因此:
1 2 3 4 5 6 |
吞下异常通常是不好的做法,但在这种情况下,我认为可以。
这是我的答案,希望会更好
https://stackoverflow.com/a/35623998/2585433
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | try { fos = new FileOutputStream(new File("...")); bos = new BufferedOutputStream(fos); oos = new ObjectOutputStream(bos); } catch (Exception e) { } finally { Stream.close(oos,bos,fos); } class Stream { public static void close(AutoCloseable... array) { for (AutoCloseable c : array) { try {c.close();} catch (IOException e) {} catch (Exception e) {} } } } |
采用
简洁大方。
在C#中,当我们离开范围时,有
1 2 3 | using(Stream s = new Stream(filename)) { s.read(); } |
我认为这是java的try-finally块的简写形式。 Java 6引入了Closable接口。因此,