Featured Post

Applying Email Validation to a JavaFX TextField Using Binding

This example uses the same controller as in a previous post but adds a use case to support email validation.  A Commons Validator object is ...

Friday, July 31, 2015

Ditch the Finally with a Try-With

When working with raw JDBC or files in Java, I always add a finally clause to make sure that my resources are closed.  This means that I have to pull a variable out of a try / catch block and do a null check at in the finally.  I typically do something like this code snippet that uses a BufferedReader.

BufferedReader br = null;
try {
    File manifestMF = new File(metaInfDir, "MANIFEST.MF");
    br = new BufferedReader(new FileReader(manifestMF));
    String line = "";
    while( (line = br.readLine()) != null ) {
 if( line.contains("Digest:") || 
  line.contains("Digest-Manifest:") || 
   line.contains("Digest-Manifest-Main-Attributes:")) {
     logger.debug("[UNZIP] line={}", line);
 }
    }

} catch(IOException exc) {
    logger.error("error processing MANIFEST.MF", exc);
} finally {
    if( br != null ) {
 try {
     br.close();
 } catch(IOException ignore) {}
    }
}

BufferedReader is pulled out of the main processing code block and consulted again in the finally code block.  A null-check and exception handler are needed in the finally block.

Java SE 7 introduced the try-with-resource syntax which allows you to put a resource like BufferedReader in a beginning declaration.  Whenever the main processing code block exits -- normally or from an exception -- BufferedReader and other resources like the newer JDBC Connection and Statement classes will be closed.  Any class that implements the AutoCloseable interface is eligible, including your own classes.

The rewritten code looks like this.  Note the absence of the finally block.

File manifestMF = new File(metaInfDir, "MANIFEST.MF");
try (
    BufferedReader br2 = new BufferedReader(new FileReader(manifestMF))
) {
    String line = "";
    while( (line = br2.readLine()) != null ) {
 if( line.contains("Digest:") || line.contains("Digest-Manifest:") || line.contains("Digest-Manifest-Main-Attributes:")) {
     logger.debug("[UNZIP 2] line={}", line);
 }
    }

} catch(IOException exc) {
    logger.error("error processing MANIFEST.MF", exc);
}

This isn't a huge time savings for me.  After years of programming in Java, I'm well conditioned to writing the finally block.  However, I have found that less experienced developers often leave off the finally block off.  And this can result in big problems.  You might not know about a resource leak until you're well after deployment to your production environment.  I suspect the problem is a lack of feedback; something can functionality pass a test and work well for a while in the lower environments before a resource is exhaustive.  In this case, getting developers to use try-with-resource might result in fewer bugs.

No comments:

Post a Comment