Java "blank final field may not have been initialized" Exception thrown in method oddness
Solution 1
No, the compiler doesn't determine that the
throwErrorMethod
will never complete normally. There's nothing in the specification to suggest it should. Unfortunately there's no way to indicate that a method will never return normally.It's only "may" because there's a potential execution path which doesn't initialize the variable. The presence of such an execution path is defined to be an error.
You may find this pair of blog posts (part 1; part 2) by Eric Lippert interesting. It's about C# rather than Java, but it's the same principle.
Solution 2
Exceptions are supposed to be exceptional. It doesn't assume that an exception is always thrown.
The compiler uses the word may
as it cannot tell if you could access an uninitialsied variable. Additionally, you may change which the method does without recompiling this class and any assumption it made would be incorrect.
If you want to throw an Exception always, you can do
final int var1;
if ( isSomethingTrue ) {
var1 = 123;
} else {
throw exceptionMethod();
}
int var2 = var1;
// later
public Exception exceptionMethod() {
return new Exception("Complex-Exception-String");
}
Solution 3
The compiler doesn't do the sort of check you are expecting. It does not determine for sure that throwErrorMethod
actually throws an exception every time. Therefore, it assumes that it's possible to go into your else
clause, invoke throwErrorMethod
, return from that method, and then not initialize var1
(which must be initialized).
Solution 4
If you want to tell the compiler that an error will definitely be thrown, but don't want to in-line the logic for constructing the error, you can do something like this:
} else {
throw createErrorMethod();
}
where createErrorMethod()
is declared to return some kind of Throwable.
krishnaz
Updated on November 17, 2020Comments
-
krishnaz over 3 years
I have some code like:
final int var1; if ( isSomethingTrue ) { var1 = 123; } else { throwErrorMethod(); } int var2 = var1;
And throwErrorMethod is defined something like:
private void throwErrorMethod() throws Exception{ throw new Exception(); }
And I get a
blank final field may not have been initialized
compile error for thevar2 = var1
statement. If I inline the method, compilation is fine!- Doesn't the compiler see the
throws Exception
on the method called? - How come an error which has the word
may
in it stops compilation?!?
- Doesn't the compiler see the
-
Mark Peters about 13 yearsUnfortunately there's no way to indicate that a method will never return normally. Is that really unfortunate?
-
Jon Skeet about 13 years@Mark: Yes. If you could tell the compile to enforce that it never returned normally, and then use that information later, it would make certain bits of code clearer... such as the code in this question, potentially. The current rules make it hard to extract into a method a block of code which will never complete normally, simply because of the way that affects definite assignment.
-
Mark Peters about 13 yearsI'm reading through the blog article by Eric. Thanks for the link.
-
Mark Peters about 13 yearsOK, done, and I see the value, thanks. Though I was for the most part distracted by all of the Princess Bride references.