The following code does not compile with javac 1.8.0_144 and ecj:
private LongSupplier foo() {
long fileSize;
try {
fileSize = canThrow();
} catch (IOException e) {
fileSize = 42;
}
LongSupplier foo = () -> 1 + fileSize;
return foo;
}
I am wondering if this a bug in the compiler. The definition of effectively final in the JLS is:
Certain variables that are not declared final are instead considered effectively final:
A local variable whose declarator has an initializer (§14.4.2) is effectively final if all of the following are true:
It is not declared final.
It never occurs as the left hand side in an assignment expression (§15.26). (Note that the local variable declarator containing the
initializer is not an assignment expression.)It never occurs as the operand of a prefix or postfix increment or decrement operator (§15.14, §15.15).
A local variable whose declarator lacks an initializer is effectively final if all of the following are true:
It is not declared final.
Whenever it occurs as the left hand side in an assignment expression, it is definitely unassigned and not definitely assigned before the assignment; that is, it is definitely unassigned and not definitely assigned after the right hand side of the assignment expression (§16 (Definite Assignment)).
It never occurs as the operand of a prefix or postfix increment or decrement operator.
A method, constructor, lambda, or exception parameter (§8.4.1, §8.8.1, §9.4, §15.27.1, §14.20) is treated, for the purpose of
determining whether it is effectively final, as a local variable
whose declarator has an initializer.
My reading is that in clause 2, the assignments in the try/catch block are allowed because fileSize
is definitely unassigned before the assignment.
I think the reasoning to explain the rejection of the code is:
- fileSize is definitely unassigned before the try block
- fileSize is assigned (definitely? It seems that 16.1.8 does not care about exceptions in the assignment) after fileSize = canThrow()
- fileSize is assigned after the try block
- fileSize is not definitely unassigned before the catch block, and thus not definitely unassigned before the assignment in the catch block.
- thus, clause 2 of 4.12.4 does not apply here
Is this correct?