Aus*_*yde 40 java resources try-catch
在研究学校项目时,我写了以下代码:
FileOutputStream fos;
ObjectOutputStream oos;
try {
fos = new FileOutputStream(file);
oos = new ObjectOutputStream(fos);
oos.writeObject(shapes);
} catch (FileNotFoundException ex) {
// complain to user
} catch (IOException ex) {
// notify user
} finally {
if (oos != null) oos.close();
if (fos != null) fos.close();
}
Run Code Online (Sandbox Code Playgroud)
问题是Netbeans告诉我resource.close()线路抛出IOException,因此必须被捕获或声明.它也抱怨oos并且fos可能尚未初始化(尽管无效检查).
这看起来有点奇怪,看到整个点是如何阻止IOException那里的权利.
我的下意识修复是这样做的:
} finally {
try {
if (oos != null) oos.close();
if (fos != null) fos.close();
} catch (IOException ex) { }
}
Run Code Online (Sandbox Code Playgroud)
但在内心深处,这让我感到困扰,感觉很脏.
我来自C#背景,我只是利用一个using块,所以我不确定处理这个问题的"正确"方法.
处理这个问题的正确方法是什么?
Ste*_*n C 53
如果您尝试从源头捕获并报告所有异常,则更好的解决方案是:
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream(file));
oos.writeObject(shapes);
oos.flush();
} catch (FileNotFoundException ex) {
// complain to user
} catch (IOException ex) {
// notify user
} finally {
if (oos != null) {
try {
oos.close();
} catch (IOException ex) {
// ignore ... any significant errors should already have been
// reported via an IOException from the final flush.
}
}
}
Run Code Online (Sandbox Code Playgroud)
笔记:
close和flush自己的包裹流等,所以你只需要关闭或刷新最外层的包装.IOException能够看到任何写入失败1.如果你经常需要"关闭一个忽略IOExceptions的可能为空的流",那么你可以自己编写一个这样的辅助方法:
public void closeQuietly(Closeable closeable) {
if (closeable != null) {
try {
closeable.close();
} catch (IOException ex) {
// ignore
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后你可以用以下代码替换之前的finally块:
} finally {
closeQuietly(oos);
}
Run Code Online (Sandbox Code Playgroud)
(另一个答案指出,一个closeQuietly方法已经在Apache Commons库中可用了......如果你不介意为你的项目添加10行方法的依赖项. 更新:请注意这些方法在版本2.6中不推荐使用API).
但请注意,您只能closeQuietly在IO异常真正无关的流上使用.
1 - 使用try-with-resources时不需要这样做.
论问题flush()与close()人们的询问:
close()写入器具有API合同,该合同声明会刷新所有缓冲的输出.您应该发现执行输出缓冲的所有其他(标准)输出类的行为方式相同.因此,对于标准类,flush()之前立即调用是多余的close().close()不刷新缓冲数据的方法都可能被破坏.最后,还有flush()实际问题.javadoc说的是这个(对OutputStream......)
如果该流的预期目的地是由底层操作系统提供的抽象,例如文件,则刷新流仅保证先前写入流的字节被传递到操作系统以进行写入; 它不能保证它们实际上写入物理设备,如磁盘驱动器.
所以...如果您希望/想象调用flush()保证您的数据将持续存在,那么您错了! (如果你需要做那种事情,看看FileChannel.force方法......)
另一方面,如果您可以使用Java 7或更高版本,则@Mike Clark的答案中描述的"新"试用资源是最佳解决方案.
如果您没有使用Java 7或更高版本来使用新代码,那么您可能陷入了深深的困境并深入挖掘.
小智 25
try/catch /最终涉及可关闭对象(例如Files)的当前最佳实践是使用Java 7的try-with-resource语句,例如:
try (FileReader reader = new FileReader("ex.txt")) {
System.out.println((char)reader.read());
} catch (IOException ioe) {
ioe.printStackTrace();
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,FileReader会在try语句结束时自动关闭,而不需要在显式finally块中关闭它.这里有几个例子:
http://ppkwok.blogspot.com/2012/11/java-cafe-2-try-with-resources.html
官方Java描述如下:
http://docs.oracle.com/javase/7/docs/technotes/guides/language/try-with-resources.html
Mik*_*ark 13
Java 7将添加自动资源管理块.它们与C#非常相似using.
Josh Bloch写了技术提案,我强烈推荐阅读.这不仅仅是因为它将为您提供即将推出的Java 7语言功能,还因为该规范激发了对这种结构的需求,并且这样做,说明了即使在没有ARM的情况下如何编写正确的代码.
这是Asker代码的一个例子,翻译成ARM形式:
try (FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos))
{
oos.writeObject(shapes);
}
catch (FileNotFoundException ex)
{
// handle the file not being found
}
catch (IOException ex)
{
// handle some I/O problem
}
Run Code Online (Sandbox Code Playgroud)