I guess many of you readers are familiar with the Open/Closed principle. It states that:
Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification
Object-Oriented Software Construction (1988)
This other Open/Closed principle is completely unrelated, but just as important. It states that:
When "something" is opened by one’s code, one MUST close it as well!
My bathroom (2014)
Simple enough? Then why do I regularly stumble upon database connections not closed (i.e. released to the pool), sockets as well, input streams not closed, output streams not closed, etc.? (But to be honest, I also am guilty of sometimes forgetting the later). When resources are not released just after their use, it might generate memory leaks. Other possible consequences are related to the resource’s nature: for example, when not releasing database connections, sooner or later the pool will be exhausted so that no new connections to the database can be acquired - and basically your application will be unusable, requiring a reboot of the application server.
Still, nothing prevents us from taking care of closing the resource, there are just some little things to address:
- As seen above, closing a resource is not an option, it must be ensured.
Java makes it possible through the
finally
block (so that a relatedtry
block is necessary as well). - Most
close()
(orrelease()
ordestroy()
or what have you) method signatures throw a checked exception. If you really want my opinion, this is a design mistake but we developers have to deal with it (and to be honest, this is not the first time someone made a decision where I had to handle the consequences of, that’s know as Management 1.0).
Here’s a very simple example:
File file = new File("/path/to/file");
FileInputStream fis = new FileInputStream(file);
try {
// Do something with file
} finally {
fis.close();
}
Note line 6 uses a method whose signature throws a checked exception and must be dealt accordingly.
As in most cases, exception thrown while closing hard hardly recoverable (read not at all), not throwing it further is more than a valid option.
Instead of further cluttering the code, just use Apache Commons IO's IOUtils.closeQuietly()
(or its database counterpart Apache Commons DB's DBUtils.closeQuitely()
).
The finally
block above can be replaced as follows:
finally {
LOGGER.log("Couldn't close input stream on file " + file.getAbsolutePath());
IOUtils.closeQuietly(fis);
}
(Yes, logging that a resource cannot be released is a good practice in all cases)
Finally (no pun intended), one might remember that Java 7 brings the AutoCloseable
interface along with the try-with-resources syntax.
This makes it even simpler to handle the close() if the method signature doesn’t throw an exception:
try (StringReader reader = new StringReader(string)){
// Do something with reader
}
StringWriter.close() signature throws an exception, even though it does nothing
|
In conclusion, remember that Continuous Integration platforms are your friend and tools such as Sonar (or Checkstyle, PMD and FinddBugs) are a good way to check unreleased resources.