Before my OCPJP studies got interrupted, I was all bent out of shape over "effectively final", having gotten a related mock question wrong and thinking how dumb it was that "final" and "effectively final" are considered disjoint categories in the JLS, because I hardly saw any point of making that distinction. I guess if something is "final" then we had better not re-assign to it or it won't compile any more, but if it is just "effectively final" that doesn't matter by itself unless someone makes use of it, for example in a local inner class or in a lambda. Alright, I guess that is a reason to track the distinction all over the specification -- reassigning a final variable is always fatal to your compilation, whereas reassigning an effectively final variable usually makes no difference, except in the cases a lambda or local inner class tries to use it. Wow, now that I calmed down I even agree.
I was wondering where I had gotten drummed into my head that ALL final variables were effectively final, rather than NONE of them, ever.
I was upset about getting the question wrong but my public defender appeared, read me the JLS and I went off to jail.
While reviewing, I found the offending source that misled me into thinking final variables were effectively final, it was the Sybex 815 book, Chapter 6.
Quoting from page 233 of Chapter 6 of the printed book:
Method parameters and local variables are allowed to be referenced if they are effectively final. This means that the value of a variable doesn't change after it is set, regardless of whether it is explicitly marked as final. If you aren't sure whether a variable is effectively final, add the final keyword. If the code would still compile, the variable is effectively final.
First sentence: True but incomplete, they are also allowed to be referenced if final as well.
Second Sentence ("This means that the value of a variable doesn't change after it is set, regardless of whether it is explicitly marked as final."): No, final variables are not considered effectively final according to the JLS consistently, certification exams, and mock exam questions I already got wrong in the past. I won't defend it beyond saying it is in the JLS and maybe I see why they make this hair-splitting distinction mused on at the top of the post.
Third sentence (" If you aren't sure whether a variable is effectively final, add the final keyword. If the code would still compile, the variable is effectively final.") True but this only proves that final variables are not effectively final, because the following code will not compile:
jshell> final final int = 7
| repeated modifier
| final final int = 7;
On page 237:
[The body of a lambda] can use any local variables or method parameters that are effectively final.
Determine whether a variable can be used in a lambda body. Local variables and method parameters must be effectively final to be referenced. This means the code must compile if you were to add the final keyword to these variables.
Same comments. The JLS wants us to consider final variables and effectively final variables two separate categories. I already got another Sybex mock exam question wrong by forgetting that. I won't fight the JLS (and for the first time today saw the distinction) but the 816 book makes very clear that effectively final and final are not the same thing. Having this contrary description in the earlier chapter makes an already confusing situation more so.
p.s. I still love the book. If I am fortunate enough to live a very, very long time I doubt I'll ever forget the definition of "effectively final" again...
I wonder how important the distinction is for anyone not implementing Java themselves, but just using it.
Nevertheless, I prefer to stick to their terminology, so even if there are no certification questions covering it (only mock ones) I will continue to always try to "Talk about Java stuff like the JLS does".
I now see another reason to separate "effectively final" from final. The "effectively final" concept does not apply to static or instance members of classes, interfaces or enums, whereas final applies to all of those. Well except instance members of interfaces which don't exist. All the others can be explicitly final but are never said to be "effectively final".
That leaves method, constructor and lambda parameters and variables as things that could be "effectively final".