Java io丑陋的try-finally块
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2699209/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java io ugly try-finally block
提问by Tom Brito
Is there a not so ugly way of treat the close()
exception to close both streams then:
是否有一种不那么丑陋的方式来处理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();
}
update: All the above code is within one more try-catch, thanks for the warnings.
更新:以上所有代码都在一个 try-catch 之内,感谢您的警告。
FINALLY (after the answers):
最后(在回答之后):
And a good utility method can be done using Execute Around idiom(thanks Tom Hawtin).
使用Execute Around idiom可以完成一个很好的实用方法(感谢 Tom Hawtin)。
采纳答案by Yishai
This is the correct idom (and it works fine):
这是正确的习惯用法(并且工作正常):
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
}
}
The reason this works fine is that the exception thrown before you got to finally will be thrown after your finally code finishes, provided that your finally code doesn't itself throw an exception or otherwise terminate abnormally.
这工作正常的原因是在你到达 finally 之前抛出的异常将在你的 finally 代码完成后抛出,前提是你的 finally 代码本身不会抛出异常或以其他方式异常终止。
Edit: As of Java 7 (and Android SDK 19 - KitKat) there is now a Try with resources syntax to make this cleaner. How to deal with that is addressed in this question.
编辑:从 Java 7(和 Android SDK 19 - KitKat)开始,现在有一个 Try with resources 语法来使这个更干净。在这个问题中解决了如何处理。
回答by Stephen C
One trick I sometimes use is to define a method called closeQuietly(Closeable)
that tests to see if its argument is null
then closes it, ignoring any exceptions. But you need to be a careful closing OutputStreams and Writers that way because they may actually throw an exception that matters; e.g. if the final flush fails.
我有时使用的一个技巧是定义一个称为closeQuietly(Closeable)
测试的方法,以查看它的参数是否null
关闭它,忽略任何异常。但是您需要小心地以这种方式关闭 OutputStreams 和 Writers,因为它们实际上可能会抛出一个重要的异常;例如,如果最终冲洗失败。
Things are likely to improve with Java 7. Reports are that it will have a new construct that provides a more concise way of handling managed resources; e.g. streams that need to be closed when they are finished with.
Java 7 的情况可能会有所改善。据报道,它将拥有一个新的结构,提供一种更简洁的方式来处理托管资源;例如,在完成时需要关闭的流。
Finally, you should be aware that your example has a bug. If the method call to open the second stream, the first stream will not be closed. The second open needs to be done inside the try
block.
最后,您应该意识到您的示例有一个错误。如果方法调用打开第二个流,第一个流将不会被关闭。第二次打开需要在try
块内完成。
回答by Adamski
You could implement a utility method:
你可以实现一个实用方法:
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) {}
}
}
}
Then your code would be reduced to:
那么您的代码将减少为:
try {
copy(in, out);
} finally {
IOUtil.closeQuietly(in, out);
}
Additional
额外的
I imagine there'll be a method like this in a 3rd party open-source library. However, my preference is to avoid unnecessary library dependencies unless I'm using a large portion of its functionality. Hence I tend to implement simple utility methods like this myself.
我想在 3rd 方开源库中会有这样的方法。然而,我的偏好是避免不必要的库依赖,除非我使用了它的大部分功能。因此,我倾向于自己实现这样的简单实用方法。
回答by leonbloy
In most cases the 'in' close() exception is irrelevant, so:
在大多数情况下,'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 */ }
}
It's usually bad practice to swallow exceptions, but in this case I think it's ok.
吞下异常通常是不好的做法,但在这种情况下,我认为没关系。
回答by Tom Hawtin - tackline
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);
}
Remember that opening a stream may throw an exception, so you do need a try
between the stream openings (please don't do some hack involving null
s. Anything can throw an Error
(which are not an instances of Exception
).
请记住,打开流可能会引发异常,因此您确实需要try
在流打开之间使用a (请不要做一些涉及null
s 的黑客攻击。任何东西都可能抛出 an Error
(不是 的实例Exception
)。
It turns out that catch
and finally
should rarely share the same try
.
事实证明,catch
和finally
应该很少共享相同的try
.
Since Java SE 7 you can write use try-with-resource to avoid so much indentation. It more or less does the same thing although there are suppressed exception hidden away.
从 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);
}
You may want to use the Execute Around idiom.
您可能想要使用Execute Around idiom。
I believe the standard good way to copy is using NIO's transferTo
/transferFrom
.
我相信复制的标准好方法是使用 NIO 的transferTo
/ transferFrom
。
回答by Istao
回答by ColinD
Guavahas very nice IO APIs that eliminate the need for this. For instance, your example would be:
Guava有非常好的 IO API,可以消除这种需要。例如,你的例子是:
Files.copy(new File(inputFileName), new File(outputFileName));
More generally, it uses the concept of InputSupplier
s and OutputSupplier
s to allow the InputStream
s and OutputStream
s to be created within its utility methods, allowing it full control over them so it can handle closing properly.
更一般地说,它使用InputSupplier
s 和OutputSupplier
s的概念来允许在其实用程序方法中创建InputStream
s 和OutputStream
s,允许它完全控制它们,以便它可以正确处理关闭。
Additionally, it has Closeables.closeQuietly(Closeable)
which is basically the type of method most of the answers have suggested.
此外,它Closeables.closeQuietly(Closeable)
基本上是大多数答案建议的方法类型。
The IO stuff in it is still in beta and subject to change, but it's worth checking out and even using, depending on what it is you're working on.
其中的 IO 内容仍处于测试阶段,可能会发生变化,但值得检查甚至使用,具体取决于您正在处理的内容。
回答by vodkhang
I strongly believe that in Java 7.0, you do not need to explicitly close the stream yourself anymore. Language Features in Java 7
我坚信在 Java 7.0 中,您不再需要自己显式关闭流。Java 7 中的语言特性
try (BufferedReader br = new BufferedReader(new FileReader(path)) {
return br.readLine();
}
回答by Val
In C#, there is using
construction that closes closable objects automatically, when we leave the scope:
在 C# 中,有一种using
构造可以在我们离开作用域时自动关闭可关闭对象:
using(Stream s = new Stream(filename)) {
s.read();
}
I think that this is a short form for java's try-finally block. Java 6 has introduced the Closable interface. So, using
is almost there. When the final step is done in Java 7, it will be terrific indeed.
我认为这是 java 的 try-finally 块的简短形式。Java 6 引入了 Closable 接口。所以,using
快到了。当最后一步在 Java 7 中完成时,确实会很棒。
回答by user3402937
Use
用
IOUtils.closeNoThrow(myInputStream);
IOUtils.closeNoThrow(myInputStream);
Simple and elegant.
简单而优雅。