[英]Java io ugly try-finally block
是否有一种不那么丑陋的方式来处理close()
异常以关闭两个流然后:
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(它工作正常):
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语法来使它更清晰。 如何处理这个问题在这个问题中得到了解决。
您可以实现一个实用工具方法:
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);
}
额外
我想在第三方开源库中会有这样的方法。 但是,我的偏好是避免不必要的库依赖,除非我使用它的大部分功能。 因此,我倾向于自己实现这样的简单实用方法。
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);
}
请记住,打开一个流可能会抛出一个异常,所以你需要在流开放之间try
(请不要做一些涉及null
的hack。任何东西都可以抛出一个Error
(它不是Exception
的实例)。
事实证明, catch
并finally
应该很少共享相同的try
。
从Java SE 7开始,您可以编写使用try-with-resource来避免这么多缩进。 尽管隐藏了被抑制的异常,它或多或少都会做同样的事情。
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的transferTo
/ transferFrom
。
Guava拥有非常好的IO API,无需使用它。 例如,您的示例是:
Files.copy(new File(inputFileName), new File(outputFileName));
更一般地说,它使用InputSupplier
和OutputSupplier
的概念来允许在其实用程序方法中创建InputStream
和OutputStream
,允许它完全控制它们,以便它可以正确处理关闭。
此外,它具有Closeables.closeQuietly(Closeable)
,这基本上是大多数答案建议的方法类型。
其中的IO内容仍处于测试阶段且可能会发生变化,但值得检查甚至使用,具体取决于您正在进行的工作。
从Java 7开始 ,就Closeable
资源而言,有一种更好的方法来编写try-finally块。
现在,您可以在try
关键字后的括号中创建资源,如下所示:
try (initialize resources here) {
...
}
并且在代码块完成后它们将自动关闭。 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
循环后,资源将被关闭!
我坚信在Java 7.0中,您不需要自己显式关闭流。 Java 7中的语言功能
try (BufferedReader br = new BufferedReader(new FileReader(path)) {
return br.readLine();
}
我有时使用的一个技巧是定义一个名为closeQuietly(Closeable)
的方法,该方法测试其参数是否为null
然后关闭它,忽略任何异常。 但是你需要谨慎关闭OutputStreams和Writers,因为它们实际上可能抛出一个重要的异常; 例如,如果最后的冲洗失败。
使用Java 7可能会有所改善。据报道,它将有一个新的构造,提供一种更简洁的方式来处理托管资源; 例如,当它们完成时需要关闭的流。
最后,您应该知道您的示例有一个错误。 如果方法调用打开第二个流,则不会关闭第一个流。 第二次打开需要在try
块内完成。
在大多数情况下,'in'close()异常是无关紧要的,因此:
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
可自动关闭可关闭对象的构造:
using(Stream s = new Stream(filename)) {
s.read();
}
我认为这是java的try-finally块的简短形式。 Java 6引入了Closable接口。 所以, using
几乎就在那里。 当最后一步在Java 7中完成时,它确实非常棒。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.