crazy idea: weaken the effectively final restriction

mark.yagnatinsky at mark.yagnatinsky at
Tue Oct 5 21:55:45 UTC 2021

I'm not sure if this is the right list for this; if not I hope someone can redirect me.

Java requires that local variables that are captured by a lambda must be effectively final.
This restriction has the benefit that no one needs to worry about annoying questions such as "what are the semantics of a data race on a local variable" and other such horrors.

But this benefit can still be obtained by a weaker restriction.  For instance, consider this code, which currently does not compile:

Runnable f(String s) {
                s = normalize(s);
                return () -> println(s); // no can do: s is not effectively final

However, this seems a bit silly because although s is not final throughout the entire method, it's final where it actually matters.
Namely, it is final from the point of capture to the end of the method, and that's the only condition we need to avoid those annoying questions.

What do we gain by allowing the code above?  Well, if we don't allow it, how can the code above be fixed?  We would have to introduce a new local variable.
That would actually be fine, except for another rule Java has, also for a good reason: one local variable name can NOT "shadow" another: all local variables must have distinct names.
That is, we can do something like this: String s = "hello"; String s = s.trim();
So we need to come up with a new name, and this has two costs:
First, coming up with good names is hard, and coming up with two good names for what is basically the same thing is harder.
Second, suppose that when we first wrote the method, the variable really was effectively final, and we needed to change it many months/years/decades later.
We now need to update the appropriate usages to the new name.  This tends to clutter line-based diffs, creating more work for reviewers during pull requests, and also for code archeologists.
Third (did I say two?): we must spend mental bandwidth deciding how to accomplish renaming things.  In the example above we have at least two options:

Runnable f(String t) {// option 1: rename original
                String s = normalize(t);
                return () -> println(s);

Runnable f(String s) {// option 2: keep original
                String t = normalize(s);
                return () -> println(t);

Deciding which option is better might actually involve non-trivial tradeoffs.  Perhaps option 1 leads to a smaller diff, but option 2 leads to a better parameter name for the method signature.
How important are good parameter names?  What if it's a private method with only one caller?  Etc.

It seems that all this nuisance would go away almost for free if we just weaken the restriction to "effectively final from point of capture".
The only possible downside I can see is that this would be a bit more annoying to properly specify in the language spec.

So... opinions?  Good idea?  Bad idea?


“This message is for information purposes only, it is not a recommendation, advice, offer or solicitation to buy or sell a product or service nor an official confirmation of any transaction. It is directed at persons who are professionals and is not intended for retail customer use. Intended for recipient only. This message is subject to the terms at:

For important disclosures, please see: regarding market commentary from Barclays Sales and/or Trading, who are active market participants; regarding our standard terms for the Investment Bank of Barclays where we trade with you in principal-to-principal wholesale markets transactions; and in respect of Barclays Research, including disclosures relating to specific issuers, please see”  
If you are incorporated or operating in Australia, please see for important disclosure.
How we use personal information  see our privacy notice 

More information about the jdk-dev mailing list