The Java 7 try-with-resources syntax (also known as ARM block (Automatic Resource Management)) is nice, short and straightforward when using only one AutoCloseable resource. However, I am not sure what is the correct idiom when I need to declare multiple resources that are dependent on each other, for example a FileWriter and a BufferedWriter that wraps it. Of course, this question concerns any case when some AutoCloseable resources are wrapped, not only these two specific classes.
I came up with the three following alternatives:
1)
The naive idiom I have seen is to declare only the top-level wrapper in the ARM-managed variable:
static void printToFile1(String text, File file) {
try (BufferedWriter bw = new BufferedWriter(new FileWriter(file))) {
bw.write(text);
} catch (IOException ex) {
// handle ex
}
}
This is nice and short, but it is broken. Because the underlying FileWriter is not declared in a variable, it will never be closed directly in the generated finally block. It will be closed only through the close method of the wrapping BufferedWriter. The problem is, that if an exception is thrown from the bw's constructor, its close will not be called and therefore the underlying FileWriter will not be closed.
2)
static void printToFile2(String text, File file) {
try (FileWriter fw = new FileWriter(file);
BufferedWriter bw = new BufferedWriter(fw)) {
bw.write(text);
} catch (IOException ex) {
// handle ex
}
}
Here, both the underlying and the wrapping resource are declared in the ARM-managed variables, so both of them will certainly be closed, but the underlying fw.close() will be called twice: not only directly, but also through the wrapping bw.close().
This should not be a problem for these two specific classes that both implement Closeable (which is a subtype of AutoCloseable), whose contract states that multiple calls to close are permitted:
Closes this stream and releases any system resources associated with it. If the stream is already closed then invoking this method has no effect.
However, in a general case, I can have resources that implement only AutoCloseable (and not Closeable), which doesn't guarantee that close can be called multiple times:
Note that unlike the close method of java.io.Closeable, this close method is not required to be idempotent. In other words, calling this close method more than once may have some visible side effect, unlike Closeable.close which is required to have no effect if called more than once. However, implementers of this interface are strongly encouraged to make their close methods idempotent.
3)
static void printToFile3(String text, File file) {
try (FileWriter fw = new FileWriter(file)) {
BufferedWriter bw = new BufferedWriter(fw);
bw.write(text);
} catch (IOException ex) {
// handle ex
}
}
This version should be theoretically correct, because only the fw represents a real resource that needs to be cleaned up. The bw doesn't itself hold any resource, it only delegates to the fw, so it should be sufficient to only close the underlying fw.
On the other hand, the syntax is a bit irregular and also, Eclipse issues a warning, which I believe is a false alarm, but it is still a warning that one has to deal with:
Resource leak: 'bw' is never closed
So, which approach to go for? Or have I missed some other idiom that is the correct one?
Here's my take on the alternatives:
1)
try (BufferedWriter bw = new BufferedWriter(new FileWriter(file))) {
bw.write(text);
}
For me, the best thing coming to Java from traditional C++ 15 years ago was that you could trust your program. Even if things are in the muck and going wrong, which they often do, I want the rest of the code to be on best behaviour and smelling of roses. Indeed, the BufferedWriter might throw an exception here. Running out of memory wouldn't be unusual, for instance. For other decorators, do you know which of the java.io wrapper classes throw a checked exception from their constructors? I don't. Doesn't do code understandability much good if you rely upon that sort of obscure knowledge.
Also there's the "destruction". If there is an error condition, then you probably don't want to be flushing rubbish to a file that needs deleting (code for that not shown). Although, of course, deleting the file is also another interesting operation to do as error handling.
Generally you want finally blocks to be as short and reliable as possible. Adding flushes does not help this goal. For many releases some of the buffering classes in the JDK had a bug where an exception from flush within close caused close on the decorated object not be called. Whilst that has been fixed for some time, expect it from other implementations.
2)
try (
FileWriter fw = new FileWriter(file);
BufferedWriter bw = new BufferedWriter(fw)
) {
bw.write(text);
}
We're still flushing in the implicit finally block (now with repeated close - this gets worse as you add more decorators), but the construction is safe and we have to implicit finally blocks so even a failed flush doesn't prevent resource release.
3)
try (FileWriter fw = new FileWriter(file)) {
BufferedWriter bw = new BufferedWriter(fw);
bw.write(text);
}
There's a bug here. Should be:
try (FileWriter fw = new FileWriter(file)) {
BufferedWriter bw = new BufferedWriter(fw);
bw.write(text);
bw.flush();
}
Some poorly implemented decorators are in fact resource and will need to be closed reliably. Also some streams may need to be closed in a particular way (perhaps they are doing compression and need to write bits to finish off, and can't just flush everything.
Verdict
Although 3 is a technically superior solution, software development reasons make 2 the better choice. However, try-with-resource is still an inadequate fix and you should stick with the Execute Around idiom, which should have a clearer syntax with closures in Java SE 8.
The first style is the one suggested by Oracle. BufferedWriter doesn't throw checked exceptions, so if any exception is thrown, the program is not expected to recover from it, making resource recover mostly moot.
Mostly because it could happen in a thread, with the thread dieing but the program still continuing -- say, there was a temporary memory outage that wasn't long enough to seriously impair the rest of the program. It's a rather corner case, though, and if it happens often enough to make resource leak a problem, the try-with-resources is the least of your problems.
Option 4
Change your resources to be Closeable, not AutoClosable if you can. The fact that the constructors can be chained implies it isn't unheard of to close the resource twice. (This was true before ARM too.) More on this below.
Option 5
Don't use ARM and code very carefully to ensure close() isn't called twice!
Option 6
Don't use ARM and have your finally close() calls in a try/catch themselves.
Why I don't think this problem is unique to ARM
In all these examples, the finally close() calls should be in a catch block. Left out for readability.
No good because fw can be closed twice. (which is fine for FileWriter but not in your hypothetial example):
FileWriter fw = null;
BufferedWriter bw = null;
try {
fw = new FileWriter(file);
bw = new BufferedWriter(fw);
bw.write(text);
} finally {
if ( fw != null ) fw.close();
if ( bw != null ) bw.close();
}
No good because fw not closed if exception on constructing a BufferedWriter. (again, can't happen, but in your hypothetical example):
FileWriter fw = null;
BufferedWriter bw = null;
try {
fw = new FileWriter(file);
bw = new BufferedWriter(fw);
bw.write(text);
} finally {
if ( bw != null ) bw.close();
}
To concur with earlier comments: simplest is (2) to use Closeable resources and declare them in order in the try-with-resources clause. If you only have AutoCloseable, you can wrap them in another (nested) class that just checks that close is only called once (Facade Pattern), e.g. by having private bool isClosed;. In practice even Oracle just (1) chains the constructors and doesn't correctly handle exceptions partway through the chain.
Alternatively, you can manually create a chained resource, using a static factory method; this encapsulates the chain, and handle cleanup if it fails part-way:
static BufferedWriter createBufferedWriterFromFile(File file)
throws IOException {
// If constructor throws an exception, no resource acquired, so no release required.
FileWriter fileWriter = new FileWriter(file);
try {
return new BufferedWriter(fileWriter);
} catch (IOException newBufferedWriterException) {
try {
fileWriter.close();
} catch (IOException closeException) {
// Exceptions in cleanup code are secondary to exceptions in primary code (body of try),
// as in try-with-resources.
newBufferedWriterException.addSuppressed(closeException);
}
throw newBufferedWriterException;
}
}
You can then use it as a single resource in a try-with-resources clause:
try (BufferedWriter writer = createBufferedWriterFromFile(file)) {
// Work with writer.
}
The complexity comes from handling multiple exceptions; otherwise it's just "close resources that you've acquired so far". A common practice seems to be to first initialize the variable that holds the object that holds the resource to null (here fileWriter), and then include a null check in the cleanup, but that seems unnecessary: if the constructor fails, there's nothing to clean up, so we can just let that exception propagate, which simplifies the code a little.
You could probably do this generically:
static <T extends AutoCloseable, U extends AutoCloseable, V>
T createChainedResource(V v) throws Exception {
// If constructor throws an exception, no resource acquired, so no release required.
U u = new U(v);
try {
return new T(u);
} catch (Exception newTException) {
try {
u.close();
} catch (Exception closeException) {
// Exceptions in cleanup code are secondary to exceptions in primary code (body of try),
// as in try-with-resources.
newTException.addSuppressed(closeException);
}
throw newTException;
}
}
Similarly, you can chain three resources, etc.
As a mathematical aside, you could even chain three times by chaining two resources at a time, and it would be associative, meaning you would get the same object on success (because the constructors are associative), and same exceptions if there were a failure in any of the constructors. Assuming you added an S to the above chain (so you start with a V and end with an S, by applying U, T, and S in turn), you get the same either if you first chain S and T, then U, corresponding to (ST)U, or if you first chained T and U, then S, corresponding to S(TU). However, it would be clearer to just write out an explicit three-fold chain in a single factory function.
Since your resources are nested, your try-with clauses should also be:
try (FileWriter fw=new FileWriter(file)) {
try (BufferedWriter bw=new BufferedWriter(fw)) {
bw.write(text);
} catch (IOException ex) {
// handle ex
}
} catch (IOException ex) {
// handle ex
}
I just wanted to build on Jeanne Boyarsky's suggestion of not using ARM but making sure the FileWriter is always closed exactly once. Don't think there are any problems here...
FileWriter fw = null;
BufferedWriter bw = null;
try {
fw = new FileWriter(file);
bw = new BufferedWriter(fw);
bw.write(text);
} finally {
if (bw != null) bw.close();
else if (fw != null) fw.close();
}
I guess since ARM is just syntactic sugar, we can't always use it to replace finally blocks. Just like we can't always use a for-each loop to do something that is possible with iterators.
I would say don't use ARM and go on with Closeable. Use method like,
public void close(Closeable... closeables) {
for (Closeable closeable: closeables) {
try {
closeable.close();
} catch (IOException e) {
// you can't much for this
}
}
}
Also you should consider calling close of BufferedWriter as it is not just delegating the close to FileWriter , but it does some cleanup like flushBuffer.
My solution is to do a "extract method" refactoring, as following:
static AutoCloseable writeFileWriter(FileWriter fw, String txt) throws IOException{
final BufferedWriter bw = new BufferedWriter(fw);
bw.write(txt);
return new AutoCloseable(){
#Override
public void close() throws IOException {
bw.flush();
}
};
}
printToFile can be written either
static void printToFile(String text, File file) {
try (FileWriter fw = new FileWriter(file)) {
AutoCloseable w = writeFileWriter(fw, text);
w.close();
} catch (Exception ex) {
// handle ex
}
}
or
static void printToFile(String text, File file) {
try (FileWriter fw = new FileWriter(file);
AutoCloseable w = writeFileWriter(fw, text)){
} catch (Exception ex) {
// handle ex
}
}
For class lib designers, I will suggest them extend the AutoClosable interface with an additional method to suppress the close. In this case we can then manually control the close behavior.
For language designers, the lesson is that adding a new feature could mean adding a lot others. In this Java case, obviously ARM feature will work better with a resource ownership transfer mechanism.
UPDATE
Originally the code above requires #SuppressWarning since the BufferedWriter inside the function requires close().
As suggested by a comment, if flush() to be called before close the writer, we need to do so before any return (implicit or explicit) statements inside the try block. There is currently no way to ensure the caller doing this I think, so this must be documented for writeFileWriter.
UPDATE AGAIN
The above update makes #SuppressWarning unnecessary since it require the function to return the resource to the caller, so itself does not necessary being closed. Unfortunately, this pull us back to the beginning of the situation: the warning is now moved back to the caller side.
So to properly solve this, we need a customised AutoClosable that whenever it closes, the underline BufferedWriter shall be flush()ed. Actually, this shows us another way to bypass the warning, since the BufferWriter is never closed in either way.
I am trying to read text file whilst running the program from a jar archive.
I come accros that I need to use InputStream to read file. The snippet of code:
buffer = new BufferedInputStream(this.getClass().getResourceAsStream((getClass().getClassLoader().getResource("English_names.txt").getPath())));
System.out.println(buffer.read()+" yeas");
At this line System.out.println(buffer.read()+" yeas"); program stops and nothing happens since then. Once you output the contents of buffer object it is not null.
What might be the problem?
From InputStream#read():
This method blocks until input data is available, the end of the stream is detected, or an exception is thrown.
So basically, the stream appears to be waiting on content. I'm guessing it's how you've constructed the stream, you can simplify your construction to:
InputStream resourceStream = getClass().getResourceAsStream("/English_names.txt");
InputStream buffer = new BufferedInputStream(resourceStream);
I'd also check to make sure that resourceStream is not-null.
You should not worry about InputStream being null when passed into BufferedInputStream constructor since it, the constructor handles null parameters just fine. When supplied with null it will just return null without throwing any exception. Also since InputStream implements AutoClosable the try-with-resources block will take care of closing your streams properly.
try (
final InputStream is = getClass().getResourceAsStream("/English_names.txt");
final BufferedInputStream bis = new BufferedInputStream(is);
) {
if (null == bis)
throw new IOException("requsted resource was not found");
// Do your reading.
// Do note that if you are using InputStream.read() you may want to call it in a loop until it returns -1
} catch (IOException ex) {
// Either resource is not found or other I/O error occurred
}
I am making a game and have started to work on a class called SaveManager, so far I have had no problems except when it comes to deleting the game.
My problem is this, .delete() returns false the majority of times, without calling an exception.
If I make a loop (below) it does eventually delete, despite me not actually changing any variables or references and the game loop itself definitely doesn't deal with the files at all, so it isn't "releasing" the file itself at any point.
public void delete(File save)
{
while (save.exists() && !save.delete())
{
i++;
}
new infoBox("Times delete called: " + i, "delete method in saveManager");
So my question is: If the reference is not from one of my classes how do I find it and remove it, allowing me to remove the above loop, which basically hijacks the game until the file is gone.
Here is the code which does deal with the file, in case I am in fact doing something wrong (God Forbid!) I'm pretty sure this does "release" the save file in question...
private void save()
{
ObjectOutputStream OOS = null;
BufferedOutputStream BOS = null;
FileOutputStream FOS = null;
try
{
File saveFile = new File(saveDirectory + hub.world.saveName + ".dat");
OOS = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(saveFile, false)));
OOS.write... (List of Objects & Strings here)
OOS.flush();
OOS.close();
game.saved = true; //Used for warning message on exit
this.setSavesList();
}
catch (Exception e)
{
new errorWindow(e, "SaveFile, I/O error");
}
finally
{
try
{
FOS.flush();
FOS.close();
BOS.flush();
BOS.close();
OOS.flush();
OOS.close();
}
catch (IOException e)
{
hub.frame.errorWindow(e, "Problem closing streams");
}
}
}
One general thing to check while dealing with files is if you're closing any opened streams before attempting to delete it.
You can't delete a file unless the stream opened is closed.
Take a look at this.
You are creating three streams, and only closing the top-most one (OOS).
You should close each stream manually. I think that will fix your problem.
Also, it's often considered good practice to put the close() in a finally block, so it definitely happens.
FileOutputStream fos = new FileOutputStream(fileName);
try
{
BufferedOutputStream bos = new BufferedOutputStream(fos);
OOS = new ObjectOutputStream(bos);
OOS.write... (List of Objects & Strings here)
OOS.flush();
OOS.close();
bos.flush();
bos.close();
game.saved = true; //Used for warning message on exit
this.setSavesList();
} catch (IOException ioe)
{
}
finally
{
fos.close();
}
Otherwise, you might flush the object output stream, and the data just gets stuck in the buffered output stream, and never gets written to the file output stream.
Here's a food for thought...from the code above, you have used a try-catch block...my guess is that one of the above operations is throwing an exception because of which the out.close() operation is getting skipped...why not add a "finally" block and close the stream there...it would definitely help you save the trouble.
Are you sure your file is actually being created? In the code snippet above you have while(!save.delete()) but later on you seem to refer to it as saveFile, these may be two different files! I would first check to see if the file even exists on the disk by doing an
if(!saveFile.exists()) {
do something here
}
if it doesnt exist, a delete will just return false, you cannot delete a file that does not exist.
If you are checking the result of delete you also need to check whether the files exists. Obviously if there is not file or it has already been deleted, delete() will return false. ;)
I ran FindBugs to check my code and it complains that method may fail to close stream:
Properties prop = new Properties();
prop.load(new FileInputStream("file.txt"));
...
Is it a mistake or just false positive? Will this stream be properly closed?
Stream handling is tedious (prior to Java 7). Before that you have to manually close the stream.
InputStream is = null;
try {
is = new FileInputStream(..);
// do something with stream
} finally {
try {
is.close();
} catch (Exception ex){
//report problem
}
}
apache commons-lang can shorten the finally clause by its IOUtils.closeQuitely(is), but note that it hides the exception
FindBugs is correct, the stream will remain open (at least until the end of the program or it is garbage collected). The stream tyou pass to the the load() method is not closed as the API states.
See: http://download.oracle.com/javase/6/docs/api/java/util/Properties.html#load%28java.io.InputStream%29
My code makes use of BufferedReader to read from a file [main.txt] and PrintWriter to write to a another temp [main.temp] file. I close both the streams and yet I was not able to call delete() method on the File object associated with [main.txt]. Only after calling System.gc() after closing both the stream was I able to delete the File object.
public static boolean delete (String str1, String str2, File FileLoc)
{
File tempFile = null;
BufferedReader Reader = null;
PrintWriter Writer = null;
try
{
tempFile = new File (FileLoc.getAbsolutePath() + ".tmp");
Reader = new BufferedReader(new FileReader(FileLoc));
Writer = new PrintWriter(new FileWriter(tempFile));
String lsCurrLine = null;
while((lsCurrLine = Reader.readLine()) != null)
{
// ...
// ...
if (true)
{
Writer.println(lsCurrLine);
Writer.flush();
}
}
Reader.close();
Writer.close();
System.gc();
}
catch(FileNotFoundException loFileExp)
{
System.out.println("\n File not found . Exiting");
return false;
}
catch(IOException loFileExp)
{
System.out.println("\n IO Exception while deleting the record. Exiting");
return false;
}
}
Is this reliable? Or is there a better fix?
#user183717 - that code you posted is clearly not all of the relevant code. For instance, those "..."'s and the fact that File.delete() is not actually called in that code.
When a stream object is garbage collected, its finalizer closes the underlying file descriptor. So, the fact that the delete only works when you added the System.gc() call is strong evidence that your code is somehow failing to close some stream for the file. It may well be a different stream object to the one that is opened in the code that you posted.
Properly written stream handling code uses a finally block to make sure that streams get closed no matter what. For example:
Reader reader = new BufferedReader(new FileReader(file));
try {
// do stuff
} finally {
try {
reader.close();
} catch (IOException ex) {
// ...
}
}
If you don't follow that pattern or something similar, there's a good chance that there are scenarios where streams don't always get closed. In your code for example, if one of the read or write calls threw an exception you'd skip past the statements that closed the streams.
Is this [i.e. calling System.gc();] reliable?
No.
The JVM may be configured to ignore your application's gc() call.
There's no guarantee that the lost stream will be unreachable ... yet.
There's no guarantee that calling System.gc() will notice that the stream is unreachable. Hypothetically, the stream object might be tenured, and calling System.gc() might only collect the Eden space.
Even if the stream is found to be unreachable by the GC, there's no guarantee that the GC will run the finalizer immediately. Hypothetically, running the finalizers can be deferred ... indefinitely.
Or is there a better fix ?
Yes. Fix your application to close its streams properly.
try using java.io.File library. here the simple sample:
File f = new File("file path or file name");
f.delete();
When you say you "close both the streams" you mean the BufferedReader and the PrintWriter?
You should only need to close the BufferedReader before the delete will work, but you also need to close the underlying stream; normally calling BufferedReader.close() will do that. It sounds like you think you are closing the stream but you aren't actually succeeding.
One problem with your code: you don't close the streams if exceptions occur. It's usually best to close the streams in a finally block.
Also, the code you posted doesn't use File.delete() anywhere? And what exactly do the ... lines do - are they re-assinging Reader to a new stream by any chance?
try using the apache commons io
http://commons.apache.org/io/description.html