Problems initializing a final variable in Java

14,707

Solution 1

On second thought, I think I just came up with a solution! - use an intermediate variable.

String fileName = null;
try{
   fileName = buildFileName();
}
catch(Exception e){
   ...
   System.exit(1);
}
FILE_NAME = fileName;

Don't know why it took me so long to think of this...

Solution 2

How about

String tempName = null;
try{
   tempName = buildFileName();
}
catch(Exception e){
   ...
   System.exit(1);
}
FILE_NAME = tempName;

Solution 3

Either

try {
   FILE_NAME = buildFileName();
} catch (Exception e){
   ...
   System.exit(1);
   throw new Error();
}

Or some prefer:

private static final String FILE_NAME = fileName();

private static String fileName() {
    try {
        return buildFileName();
    } catch (Exception e){
        ...
        System.exit(1);
        throw new Error();
    }
}

But calling System.exit in a static initialiser is probably a bad idea. It's going to mess your unit tests up.

Solution 4

I would personally just throw an Error -- if your error flow is properly designed, the System.exit() should be redundant. Your program presumably doesn't plough on into the wilderness if an Error is thrown...?

Share:
14,707
froadie
Author by

froadie

Updated on June 05, 2022

Comments

  • froadie
    froadie almost 2 years

    I keep running into slight variations of a problem in Java and it's starting to get to me, and I can't really think of a proper way to get around it.

    I have an object property that is final, but dynamic. That is, I want the value to be constant once assigned, but the value can be different each runtime. So I declare the class level variable at the beginning of the class - say private final FILE_NAME;. Then, in the constructor, I assign it a value - say FILE_NAME = buildFileName();

    The problem begins when I have code in the buildFileName() method that throws an exception. So I try something like this in the constructor:

    try{
       FILE_NAME = buildFileName();
    }
    catch(Exception e){
       ...
       System.exit(1);
    }
    

    Now I have an error - "The blank final field FILE_NAME may not have been initialized." This is where I start to get slightly annoyed at Java's strict compiler. I know that this won't be a problem because if it gets to the catch the program will exit... But the compiler doesn't know that and so doesn't allow this code. If I try to add a dummy assignment to the catch, I get - "The final field FILE_NAME may already have been assigned." I clearly can't assign a default value before the try-catch because I can only assign to it once.

    Any ideas...?

  • froadie
    froadie about 14 years
    thanks :) I've been facing this problem for a while, and this only just hit me... Should've been an automatic reaction to the problem as it seems to have been with you
  • Ryan Elkins
    Ryan Elkins about 14 years
    Heh, yeah. I think you beat me to it by just a few seconds ;)
  • Brett
    Brett about 14 years
    That's ugly - you don't want the = "".
  • froadie
    froadie about 14 years
    @Tom Hawtin - true. It should probably be initialized to null just from an ideal design perspective. But practically, it could be initialized to just about anything, as it's either going to be immediately replaced or the program will crash. But I'll change it just to be correct
  • Brett
    Brett about 14 years
    No, not null either. IT SHOULD NOT BE ASSIGNED.
  • froadie
    froadie about 14 years
    In the first example - why does throwing a new error make it pass the compiler? And why is it less ugly to add a line that will never be reached than it is to assign a temporary string a default value?
  • Alexander Pogrebnyak
    Alexander Pogrebnyak about 14 years
    @Tom Hawtin: You have to initialize fileName to something. If you don't you would get The local variable fileName may not have been initialized compile error. null is definitely a good choice.
  • Brett
    Brett about 14 years
    @froadie The details of the definite assignment rules are in the JLS. They are very tedious, but you should be able know what is going on by example. The compiler is required to detect that the variable is definitely assigned if an exception is not caught, and if an exception is caught the code leaves via an exception and is therefore not required to definitely assign the variable. (For final instance fields there are sneaky ways to look at the uninitialised variable before or after.)
  • Brett
    Brett about 14 years
    @Alexander Pogrebnyak No you don't. Not if you definitely do not read the variable again.
  • froadie
    froadie about 14 years
    ok. but why is this a better method? the throw new Error() line will never be reached and is just there to placate the compiler. I don't see the advantage of this answer over the one I posted and Ryan Elkin's - let me know if you think there's something I'm missing
  • Ryan Elkins
    Ryan Elkins about 14 years
    @Tom: You WILL get a compiler error if you just change it to 'String fileName;'. That variable has to be initialized to SOMETHING for this example to compile. It sounds like you're talking about a different solution rather than just not initializing the temp variable.
  • ILMTitan
    ILMTitan about 14 years
    @froadie I would argue it is better because there is less noise (1 line vs 2) and the noise is restricted to the error handling code.
  • Alexander Pogrebnyak
    Alexander Pogrebnyak about 14 years
    @Tom Hawtin: Have to initialize variable to NULL for the same token your fileName() function has to throw Error( ) after System.exit( 1). For compiler System.exit is just another function and it needs a special terminator in the block. Granted, you could put fileName = null; after System.exit instead of initializing it at the declaration line. BTW, I do think that your solution is cleaner.
  • arkon
    arkon almost 11 years
    -1 This does not even attempt to answer the OPs actual question.