How to Deal with IOException When File Already Checked for Existence

exceptionsjava

This is a specific question here, but I'm interested in the general "best practice" for similar situations as I'm new to Java.

Suppose I have Java code that needs to open a file (see below for code). I first have a function that checks for the files existence. If the file exists, we call functions to open it and process it. Otherwise we return a message to the user stating the file could not be found.

Now in the functions that open the file, we still need to have a try/catch statement for the possible IOException because it's a checked exception. The function openSpecifiedFile has to return a FileInputStream. The fact that our file was proven to exist several milliseconds ago is not enough to guarantee the catch statement will never be executed (though it's unlikely) so I'd rather not return a null here.

Is there away to return a default object instead, or just avoid the null return statement all together and exit the program with some kind of runtime exception? The only way things could go bad here is if something very bad had happened I feel…

I suppose the general question is "When running checks to ensure certain checked exceptions shouldn't occur, what is a good way to deal with the necessary try/catch blocks?"

 public static void main(String[] args) {
    String filename = args[0];
    if (specifiedFileExists(filename)) {
        FileInputStream specifiedFile = openSpecifiedFile(filename);
        processFile(specifiedFile);
    } else
        System.out.println("The specified file does not exist");
}


private static boolean specifiedFileExists(String filename) {
    File currentFile = new File(filename);
    return currentFile.exists();
}

private static FileInputStream openSpecifiedFile(String filename) {
    try {
        return new FileInputStream(filename);
    } catch (IOException e) {}
    return null;
}

private static void processFile(FileInputStream currentFile) {
    ByteBuffer filledBuffer = fillBufferFromFile(currentFile);
    String messageFromFile = processBufferToString(filledBuffer);
    System.out.println(messageFromFile);
}

private static ByteBuffer fillBufferFromFile(FileInputStream currentFile) {
    try {
        FileChannel currentChannel = currentFile.getChannel();
        ByteBuffer textBuffer = ByteBuffer.allocate(1024);
        currentChannel.read(textBuffer);
        textBuffer.flip();
        return textBuffer;
    } catch (IOException e) {}
    return ByteBuffer.allocate(0);
}

private static String processBufferToString(ByteBuffer filledBuffer) {
    StringBuilder characterBuilderFromFile = new StringBuilder();
    while (filledBuffer.hasRemaining())
        characterBuilderFromFile.append((char) filledBuffer.get());
    return characterBuilderFromFile.toString();
}

Best Answer

While @gnasher729's suggestion is probably the best answer in this specific situation, there is a more general question here, which is (paraphrasing): "how do I handle checked exceptions that shouldn't ever happen?" And in cases where you cannot use them to eliminate a redundant (and potentially incorrect) check, the best alternative is to probably rethrow them as an unchecked exception. In most of my projects, I usually end up with an exception that looks like this:

 public class UnexpectedException extends RuntimeException
 {
       public UnexpectedException (Throwable cause, String whyItShouldntHaveHappened)
       { 
           super ("Caught an exception with description: " + cause.toString() + 
                  "\nThis shouldn't have happened because: " + whyItShouldntHaveHappened, 
                  cause); 
       }
 }

UnexpectedException is then handled at the top level of the application and is logged everywhere you could possibly think of logging it. Even if logging is turned off. Because any occasion where one actually gets thrown is direct evidence of a bug. It has no constructors other than the one shown, because you always need both parameters.

Related Topic