Consider this example:
public class FileAppender implements AutoCloseable {
private final FileWriter fileWriter;
private final BufferedWriter bufferedWriter;
public FileAppender(String fileName) throws IOException {
fileWriter = new FileWriter(fileName, true)
bufferedWriter = new BufferedWriter(fileWriter);
}
public void appendLine(String line) throws IOException {
bufferedWriter.write(line + "\n");
}
@Override
public void close() throws Exception {
bufferedWriter.close();
fileWriter.close();
}
}
Here we keep an unused FileWriter
as a member of the class, just so we can manually close it later. There are many tutorials in the web which show examples like this where multiple streams are closed manually.
We could instead implement the same class more concisely:
public class FileAppender implements AutoCloseable {
private final BufferedWriter writer;
public FileAppender(String fileName) throws IOException {
writer = new BufferedWriter(new FileWriter(fileName, true));
}
public void appendLine(String line) throws IOException {
writer.write(line + "\n");
}
@Override
public void close() throws Exception {
writer.close();
}
}
Same applies to the usage of FileReader
and BufferedReader
.
Would there be any difference between the above two implementations?
With BufferedWriter
, specifically, you can just use close
on the BufferedWriter
and it will call close
on the underlying FileWriter
.
But, as far as I'm aware, that's not documented, and not required of Writer
implementations that wrap other Writer
s (and similarly, streams). I'm paranoid, and tend to close things explicitly (in reverse order of opening them).
You can see the close operation in the BufferedWriter
source (this example is from JDK 11.0.1), though you have to look fairly closely:
public void close() throws IOException {
synchronized (lock) {
if (out == null) {
return;
}
try (Writer w = out) {
flushBuffer();
} finally {
out = null;
cb = null;
}
}
}
Note the use of try-with-resources to auto-close out
(via w
).