Case Study 1
final String someString = "Hello World";
try {
someString = "Hello";
} catch (RuntimeException e) {
someString = "World";
}
If we compile this code, we get two errors:
Cannot assign a value to final variable ‘someString’ // Line 3
Cannot assign a value to final variable ‘someString’ // Line 5
This, I understand. It’s a final variable, you’ve already assigned a reference to it, and you cannot change it anymore. Nice.
Case Study 2
final String someString;
try {
someString = "Hello";
} catch (RuntimeException e) {
someString = "World";
}
If we compile this code, we get only one error:
Variable ‘someString’ might already have been assigned to // Line 5
This, I don’t understand. We are allowed to initialize in the try block. Still, if something fails, even before the actual initialization is done, we’re not allowed to initialize the final variable in the catch block.
Why is that so? I was expecting we could initialize the variable in the catch block as the try block failed anyways.
>Solution :
tl;dr: When we reach the catch-block the try-block has failed, but we don’t know where it failed. It might have failed before, during or after assigning to the variable. Therefore the compiler can’t allow a possible re-assignment to a final variable.
Long answer: A final variable has to be assigned exactly once before it can be read. Not less (i.e. never assigned), not more (i.e. assigned twice). Exactly once.
For this reason the following code is trivially wrong:
final String someString;
someString = "Hello";
someString = "World";
The second assignment will result in a compile time error, since someString was definitely already assigned.
Now let’s look at this code:
final String someString;
try {
callSomeMethod();
someString = "Hello";
callSomeOtherMethod();
} catch (Exception e) {
someString = "World";
}
Now we’ve run into a problem: the compiler can’t know when the exception that causes the catch-block to be executed is thrown: it could be thrown in callSomeMethod() or in callSomeOtherMethod() (or through some miraculous internal problem even when trying to assign the constant).
So the compiler simply doesn’t know if someString will have been already been assigned to inside the catch-block or not (and both options would theoretically be possible at runtime!). If the variable had been assigned, then the assignment has to be a compile time error. If it wasn’t it would be fine. But since static analysis can’t tell you which one it is, the compiler has to mark the whole assignment as an error.
Now in theory in some corner cases the compiler could theoretically know that a variable was definitely assigned in the try block, even when an exception occurs. Specifically if it’s the first action and it can prove that the assignment action can not throw an exception. But if that’s the case, then the programmer can just trivially move that assignment out of the try-block and avoid the whole problem. That’s probably why no such rule exists in the JLS.