嵌套资源获取是否需要在Java中进行特殊处理



首先,是的,尝试使用资源修复这些问题中的任何一个。。。但如果没有它,我看不出这是怎么回事。

让我们以java文档中的这段代码为例,它可以在这里找到:

static String readFirstLineFromFileWithFinallyBlock(String path)
throws IOException {
BufferedReader br = new BufferedReader(new FileReader(path));
try {
return br.readLine();
} finally {
if (br != null) br.close();
}
}

现在,如果已获取资源,则会在br.close()上释放该资源。然而,

  • 如果new FileReader(path)成功,然后new BufferedReader(...)抛出异常,会发生什么
  • java如何保证FileReader关闭
  • 是否保证在已打开的FileReader上创建BufferedReader始终成功?如果是,为什么该方法被声明为抛出IOException

或者我们应该写以下内容来确保这种情况不会发生?

static String readFirstLineFromFileWithFinallyBlock(String path)
throws IOException {
FileReader fr;
try {
FileReader fr = new FileReader(path);
BufferedReader br;
try {
BufferedReader br = new BufferedReader(fr);
return br.readLine();
} finally {
if (br != null) br.close();
}
finally {
// Implements closeable, so it is ok if we call it twice.
if (fr != null) fr.close();
}
}

当然,使用try-with-resources,这种嵌套的混乱仍然会消失,因为我们可以在同一语句中声明多个资源。但我总是认为自己写"尝试资源"是为了避免思考这种情况,并试图在网上找到解决方案,但我真的做不到。

任何帮助都将不胜感激,谢谢!

教程通常已经过时或没有描述好的实践。

如果我们看看你引用的第一段代码,br永远不可能是nullif ( )可以移除。这可能是由于之前的代码将finallycatch混合而导致的。如果一个try语句同时包含finallycatch,那么它可能是错误的,而且几乎可以肯定是在做一些不明智的事情。通常情况下,你会看到一个null舞蹈正在进行,并且至少有一个明显的bug。

在这个问题上,公认的观点是,只有当你的整个过程出现严重问题时,BufferedReader才会失败。可能内存不足或堆栈溢出。如果你遇到这样的例外情况,你可能想完全摆脱。

在不尝试使用资源的情况下编写代码的迂腐方式是:

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

然而,在某些情况下,你可能会误解这一点。考虑BufferWriter。你忘了flush了,是吗?我的意思是,我会的。如果你在finally中关闭它,它就不会成为问题。还有一些装饰器本身就是资源。例如,它们可能有一个使用非垃圾回收内存的本机实现。这不一定有记录。

关闭resource和decorator并不困难,但在没有尝试使用resource的情况下确实有点向右移动。

// (Using same example even though it doesn't matter here - imaging a Writer)
FileReader fr = new FileReader(path);
try {
BufferedReader br = new BufferedReader(fr);
try {
return br.readLine();
} finally {
br.close();
}
} finally {
fr.close();
}

在java源代码中查看BufferedReaderclose()实现。

* @see FileReader
* @see InputStreamReader
* @see java.nio.file.Files#newBufferedReader
*
* @author      Mark Reinhold
* @since       1.1
*/
public class BufferedReader extends Reader {
private Reader in;
...
public void close() throws IOException {
synchronized (lock) {
if (in == null)
return;
try {
in.close();
} finally {
in = null;
cb = null;
}
}
}
...
/**
* Creates a buffering character-input stream that uses an input buffer of
* the specified size.
*
* @param  in   A Reader
* @param  sz   Input-buffer size
*
* @exception  IllegalArgumentException  If {@code sz <= 0}
*/
public BufferedReader(Reader in, int sz) {
super(in);
if (sz <= 0)
throw new IllegalArgumentException("Buffer size <= 0");
this.in = in;
cb = new char[sz];
nextChar = nChars = 0;
}
/**
* Creates a buffering character-input stream that uses a default-sized
* input buffer.
*
* @param  in   A Reader
*/
public BufferedReader(Reader in) {
this(in, defaultCharBufferSize);
}

所以close()会处理Reader(此处为FileReader)并将其设置为null。
简单地说BufferedReader br = new BufferedReader(new FileReader(path))就是好的

嵌套资源获取是否需要在Java中进行特殊处理?


此处:无

如果新的FileReader(路径)成功,然后新的BufferedReader(…)抛出异常,会发生什么?

BufferedReader构造函数不抛出异常。特别是,它不涉及任何文件系统操作,因此不会抛出IOException。

java如何保证FileReader关闭?

BufferedReader的close方法关闭底层FileReader。

是否保证在已打开的FileReader上创建BufferedReader始终成功?如果是,为什么该方法被声明为抛出IOException?

你关注的是错误的事情。readFirstLineFromFileWithFinallyBlock标记为throws IOException,因为除了BufferedReader构造函数之外调用的每个方法或构造函数都可以引发IOException。readlinecloseFileReader构造函数都可以抛出。


如果FileReader和BufferedReader构造函数都可能失败,并且如果两个对象都需要单独关闭,则需要两个trys。

您可以使用try with resources,而不是单独释放资源。请查看下面的代码。

try(BufferedReader bufferedReader = new BufferedReader(new FileReader(""))) {
}catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

最新更新