Woozle Wuzzle
That nasty java.io.IOException

I constantly run across code that looks like:

public class FileReader {
    ...
    /**
     * <p>Reads the file with the specified name and returns the 
     * contents in a {@link java.nio.ByteBuffer buffer}.</p>
     * 
     * @param  filename the name of the file to read
     * @return an allocated (not direct) <code>ByteBuffer</code> 
     *         with the contents of the file
     * @throws IOException if an I/O error occurs
     */
    public ByteBuffer readFile(final String filename)
        throws IOException
    {
        ...
    }
    ...
}

What's wrong with that? you're probably asking yourself. It's even got comments! The title of this entry should give you a little clue. I will spare you the rant and soap box about the proper use of exceptions and attempt to appeal to your common sense: If you, as the developer of the function, couldn't handle or recover from the IOException, what makes you believe that someone calling the function (someone that has little notion of what's actually going on in the function) can do something with it?

The interface or contract that you expose should not break encapsulation. The fact that you (as the developer) have I/O issues to deal with doesn't need to be exposed out to the user. What the user cares about is: did the function succeed or not, and if not, are there cases that they can possibly recover from. A more sane interface might look like the following:

public class FileReader {
    ...
    /**
     * <p>Reads the file with the specified name and returns the 
     * contents in a {@link java.nio.ByteBuffer buffer}.</p>
     * 
     * @param  filename the name of the file to read
     * @return an allocated (not direct) <code>ByteBuffer</code> 
     *         with the contents of the file
     * @throws NoSuchFileException if there is no file with the specified
     *         name
     * @throws ReadFailedException if there was any unrecoverable
     *         problem while reading the file
     */
    public ByteBuffer readFile(final String filename)
        throws NoSuchFileException, ReadFailedException
    {
        ...
    }
    ...
}

This interface throws two exceptions: NoSuchFileException and ReadFailedException. The former is "recoverable" by the user in that they may have specified the filename incorrectly and they can do something about that. The latter tells the user that it just didn't work and there's nothing that they can do about it.

What's more is that by not throwing IOException the developer is forced to look at each case explicitly and determine how each one should be handled. How many times has a handlable IOException bubbled out of an interface unexpectedly due to the throws clause? Personally, I will leave off the throws clause (or comment it out) while I'm developing a function to ensure that I'm not letting anything slip by. In the later Eclipse milestones you can now select an exception in the throws clause and it will mark each occurrance in the function that throws that exception. This is invaluable.

The next time that you are developing an interface, think about how a user will use that interface. Get into their shoes and think about their concerns. And most importantly, make sure that you're not breaking your own encapsulation.

Comments
Post a comment













Remember personal info?






Creative Commons License Unless otherwise expressly stated, all original material of whatever nature created by Rob Grzywinski and included in this weblog and any related pages, including the weblog's archives, is licensed under a Creative Commons License.