Search code examples
javavariablesdynamicexceptionfinal

Can an object dynamically loaded with possible exceptions be declared as final?


At first I was going to make the question solely about the Image class, but I wanted to make it as broadly applicable as possible.

Basically, here's the scenario. I'm making a file for GUI constants, and in this file I'd like to have final variables for each of the Images I'm using. So my fields are declared like this UP_ARROW is:

public static final Image UP_ARROW;

Then I try to load them when the ImageIO API, like so:

static {
    UP_ARROW = ImageIO.read(new File("img/upArrow.png"));
}

Unfortunately, this isn't valid, compilable code, because it explicitly throws IOException, which I have to deal with. So I modify it and surround it with a try/catch:

static {
    try {
        UP_ARROW = ImageIO.read(new File("img/upArrow.png"));
    }
    catch(IOException ioe) {
        //TODO
    }
}

Now I get a different compiler error. This time it says there's a possibility that the field may not have been initialized. Okay, that makes sense. Thank you for pointing that out to me, compiler. That seems like an easy fix:

static {
    try {
        UP_ARROW = ImageIO.read(new File("img/upArrow.png"));
    }
    catch(IOException ioe) {
        UP_ARROW = null;
    }
}

Now, no matter what, the UP_ARROW must be populated with either my image or null. I'm prepared to declare victory and move on. But now I get another, unexpected compiler error:

The final field UP_ARROW may already have been assigned

... Foiled again, compiler!

Hence the question: is there any way to get around this, such that I can dynamically load final fields at runtime? Or do I declare defeat and simply make the Images non-final?

Also, an explanation as to why the compiler won't allow this would be helpful as well. As I understand it, based on the code above, the UP_ARROW object could not have been assigned before reaching the catch{} block, because that's what must have thrown the exception. So if the try{} executes successfully, only one assignment takes place. If it does not execute successfully, still only one assignment take place. How is that not valid?


Solution

  • The following should do it:

    static {
        Image up_arrow = null;
        try {
            up_arrow = ImageIO.read(new File("img/upArrow.png"));
        }
        catch(IOException ioe) {
            // log the error?
        }
        UP_ARROW = up_arrow;
    }
    

    It might make sense to enclose the final assignment in a finally block .