Reputation: 1
I understand this as a standard part of functional programming.. my question is to why the compiler cannot automatically declare a copy of the variable as final just before the lambda statement begins?
import java.util.stream.IntStream;
public class Example
{
public static void main( String args[] )
{
int i = 5;
i = 6;
IntStream.range(0, 10).mapToLong( j-> i * j ).sum();
}
}
fails... with "Local variable i defined in an enclosing scope must be final or effectively final" whereas it seems the compiler should be smart enough to do something like this
import java.util.stream.IntStream;
public class Example
{
public static void main( String args[] )
{
int i = 5;
i = 6;
final int _i = i;
IntStream.range(0, 10).mapToLong( j-> _i * j ).sum();
}
}
the compiler could enforce that the finalized variable is never modified by the lambda function
Upvotes: 1
Views: 472
Reputation: 122439
But what if the lambda were passed somewhere which used it asynchronously (i.e. it can run after the current function ends), and you modify the variable i
in the function scope after the creation of the lambda?
int i = 5;
i = 6;
useLambdaAsynchronously( j-> i * j );
i = 7;
The lambda would still have captured a value of 6 for i
, but i
(which is supposed to be the same variable, because you have only declared one i
) now has the value of 7 in another scope. This is inconsistent, as the programmer should expect that a single variable has a single value at a time. If the lambda is run later, it will still use the value of 6 for i
even though 7 has already been assigned to i
previously.
To avoid this problem, the compiler would need to ensure that the variable is not assigned in the lambda and the variable is not assigned in the original function scope after the creation of the lambda. But that would lead to the situation where an assignment earlier in a function is allowed but later in the same function is disallowed (just because it has been captured by a lambda), which may also be surprising to the programmer. For simplicity, Java just disallows assignments anywhere.
Upvotes: 0
Reputation: 43661
Well, the compiler would actually do it if your variable i
were effectively final.
public static void main( String args[] )
{
int i = 5;
IntStream.range(0, 10).mapToLong( j-> i * j ).sum();
}
However with the second assignment i = 6;
you're making it not "effectively final", you're indicating that you actually want it to be mutable.
So why in this case should the compiler make a final copy of your variable despite you signalling that you want it to be mutable?
Upvotes: 1