Java io丑陋的try-finally块

有没有一种不那么丑陋的方式来处理close()exception来closures两个stream然后:

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

更新:所有上述代码是在一个更多的尝试赶上,感谢警告。

最后(答案之后):

使用Execute Around idiom (感谢Tom Hawtin)可以使用一个很好的实用方法。

这是正确的idom(它工作正常):

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

这可以正常工作的原因是,最终得到代码之前抛出的exception终于会抛出,只要你最后的代码本身不抛出exception或以其他方式exception终止。

编辑:从Java 7(和Android SDK 19 – KitKat),现在有一个尝试使用资源语法,使这个更清洁。 如何处理这个问题就是在这个问题上解决的 。

你可以实现一个实用的方法:

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

那么你的代码将被缩减为:

 try { copy(in, out); } finally { IOUtil.closeQuietly(in, out); } 

额外

我想在第三方开源库中会有这样的方法。 但是,我的首选是避免不必要的库依赖项,除非我使用其大部分function。 所以我倾向于实现这样的简单的实用方法。

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

请记住,打开一个stream可能会抛出一个exception,所以你需要在stream开始之间try (请不要做一些涉及null的攻击,任何事情都可以抛出一个Error (这不是Exception一个实例)。

事实certificate, catchfinally应该很less分享同样的try

从Java SE 7开始,您可以使用try-with-resource来避免太多的缩进。 它或多或less做同样的事情,虽然有抑制exception隐藏。

 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 idiom 。

我相信标准的复制方法是使用NIO的transferTo / transferFrom

番石榴有非常好的IO API,消除了这个需要。 例如,你的例子是:

 Files.copy(new File(inputFileName), new File(outputFileName)); 

更一般地说,它使用InputSupplierOutputSupplier的概念来允许在其实用方法中创buildInputStreamOutputStream ,允许它们完全控制它们,以便能够正确地处理closures。

此外,它有Closeables.closeQuietly(Closeable) ,这基本上是大多数答案build议的方法的types。

IO中的东西还在testing阶段,可能会有所变化,但是值得检查甚至使用,这取决于你在做什么。

我坚信,在Java 7.0中,你不需要明确地closures自己的stream。 Java 7中的语言特性

 try (BufferedReader br = new BufferedReader(new FileReader(path)) { return br.readLine(); } 

Java 7开始 ,关于可Closeable资源的编写try-finally块有更好的方法。

现在,您可以在try关键字之后的括号中创build资源,如下所示:

 try (initialize resources here) { ... } 

代码块完成后,它们将自动closures。 finally部分是没有必要的。

一个例子

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

for循环完成后,资源将被closures!

你有,在IOUtils ,一些closely静静的方法。

我有时使用的一个技巧是定义一个名为closeQuietly(Closeable)的方法,testing它的参数是否为null然后closures它,忽略任何exception。 但是,您需要小心地closuresOutputStreams和Writers,因为它们实际上可能会抛出一个非常重要的exception; 例如,如果最终刷新失败。

随着Java 7的发展,情况可能会有所改善。报告指出,它将有一个新的构造,提供了一个更简洁的方式来处理托pipe资源。 例如在完成时需要closures的stream。

最后,你应该知道你的例子有一个错误。 如果方法调用打开第二个stream,则第一个stream将不会被closures。 第二次打开需要在try块内完成。

在大多数情况下,“in”close()exception是不相关的,所以:

  try { copy(in, out); } finally { try { in.close() } catch (Exception e) { /* perhaps log it */ } try { out.close() } catch (Exception e) {/* perhaps log it */ } } 

吞下例外通常是不好的做法,但在这种情况下,我认为没关系。

使用

IOUtils.closeNoThrow(myInputStream);

简单而优雅。

这是我的回答,希望好多了

https://stackoverflow.com/a/35623998/2585433

 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#中,当我们离开作用域时,会using自动closures可closures对象的构造:

 using(Stream s = new Stream(filename)) { s.read(); } 

我认为这是java的try-finally块的一个简短forms。 Java 6引入了Closable接口。 所以,几乎在那里使用。 当最后一步在Java 7中完成时,确实会非常棒。