Problems initializing a final variable in Java
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...?
froadie
Updated on June 05, 2022Comments
-
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 - sayFILE_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 about 14 yearsthanks :) 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 about 14 yearsHeh, yeah. I think you beat me to it by just a few seconds ;)
-
Brett about 14 yearsThat's ugly - you don't want the
= ""
. -
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 about 14 yearsNo, not
null
either. IT SHOULD NOT BE ASSIGNED. -
froadie about 14 yearsIn 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 about 14 years@Tom Hawtin: You have to initialize
fileName
to something. If you don't you would getThe local variable fileName may not have been initialized
compile error.null
is definitely a good choice. -
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 about 14 years@Alexander Pogrebnyak No you don't. Not if you definitely do not read the variable again.
-
froadie about 14 yearsok. 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 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 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 about 14 years@Tom Hawtin: Have to initialize variable to NULL for the same token your
fileName()
function has tothrow Error( )
afterSystem.exit( 1)
. For compilerSystem.exit
is just another function and it needs a special terminator in the block. Granted, you could putfileName = null;
afterSystem.exit
instead of initializing it at the declaration line. BTW, I do think that your solution is cleaner. -
arkon almost 11 years-1 This does not even attempt to answer the OPs actual question.