July 18, 2006

Programming in the small - finally.

Following on from the previous article in the series, there are some "programming in the small" style things that I don't see as often as I'd expect.

"Non-structured programming" - using finally

Consider the following (Java) code:

	int readValue() throws IOException {
		InputStream file = new FileInputStream("temp.txt");
		int result;
		try {
			result = file.read();
		} finally {
			file.close();
		}
		return result;
	}

This can be written slightly shorter, and I think slightly better:

	int readValue() throws IOException {
		InputStream file = new FileInputStream("temp.txt");
		try {
			return file.read();
		} finally {
			file.close();
		}
	}

However, I hardly ever see other people using this style. This way of using finally came up when writing a previous article with Bjorn Freeman-Benson - he likes this style too. I don't expect to see this style all the time - just a lot more than I do, which is hardly ever.

Comments:

Comments aren't working at the moment, but here's one by email from David Peterson (and he's right, you know. I've altered the code as David's suggestion - I originally had the code working but a bit wrong due to "brain fart"). (David's "I got rejected (blacklisted)" applies to everyone at the moment).

Hi Ivan,

It's better not to put the creation of the stream within the try.. finally. If the constructor throws an exception then you will end up calling close() on a null reference.

So, an even shorter (and safer) version is...

    int readValue() throws IOException {
        InputStream stream = new FileInputStream("temp.txt");
        try {
            return stream.read();
        } finally {
            stream.close();
        }
    }

David

P.S. I tried posting a comment, but I got rejected (blacklisted). :-(

Another comment, from Adewale Oshineye:

There's a reason people don't write methods like the one in your
example. The IOException that's thrown can be misleading. The call to
read() can throw an exception which then gets buried if the call to
close() also throws an exception.

The smallest safe version of that method looks something like:

int readValue() throws IOException {
       InputStream inputStream = new FileInputStream("temp.txt");
       try {
               return inputStream.read();
       } finally {
               try {
                       inputStream.close();
               } catch (IOException e) {
                       //we can't do anything about this except log it
                       LOG.warn("Problem closing inputStream", e);
               }
       }
}

My response: Thanks for the comment - I should have picked a better example - catching the possible IOException from the close is unrelated to the point of having a return inside a try finally and some code you want to execute after the return and my example has detracted from that point.

Posted by ivan at July 18, 2006 8:39 PM
Copyright (c) 2004-2007 Ivan Moore
Comments

A good explanation for the lack of sightings is this well-worn advice: "Have one exit point". Like all other rules, it was made to be broken. But maintainers like me are grateful when the rule is honored.

Dave Harris

Posted by: Dave Harris at July 23, 2006 2:01 PM

I wonder whether logging the error on close() really matters when there is a read failure. I think that in most situations, I'd want the exception from close() only if I hadn't produced a read exception. The logic for that would look a little odd in the code, though.

I had to do something similar recently when writing a tool that was supposed to throw exceptions in the context of JUnit. If I remember correctly, an exception thrown in tearDown hides an exception thrown in the test body, so I had to encode some odd logic to get good effects.

Posted by: Michael Feathers at August 6, 2006 2:34 PM