Re: Why is that in JDK8: value used in lambda expression shuld be
effectively final?
On 02/01/13 12:51, jeti789@web.de wrote:
I'm currently plaing with JDK8 and using lambda-8-b69-windows-i586-17_dec_2012. I wonder why this does not compile:
List<Integer> ints = new ArrayList<>();
ints.add(1);
ints.add(2);
ints.add(3);
int sum = 0;
ints.forEach(i -> {sum += i;});
The compiler error is "value used in lambda expression shuld be effectively final"
It's the same reason why inner classes can't mutate local variables in
the enclosing scope. The method that accepts the lambda or inner class
instance cannot formally make any guarantee not to invoke the supplied
code in a non-serial way.
forEach could informally specify that it will execute its argument only
on its calling thread, and not after it returns, but the compiler could
not detect that guarantee and allow 'sum' to be modified.
(I'm using 'formal' to indicate something that can be detected by the
compiler.)
However, this here compiles:
int sumArray[] = new int[] { 0 };
ints.forEach(i -> {sumArray[0] += i;});
Ultimately, the compiler can't stop anyone from shooting themselves in
the foot. You can still access an instance variable unsafely via a
lambda, for example.
Stopping the protection at the level of local variables could seem a bit
arbitrary, but it is still useful, since you expect the use of local
variables to be intrinsically thread-safe (and they remain so under this
level of protection), and trying to provide more comprehensive
protection would be increasingly difficult.
I'm a bit confused now. Does this mean that JDK8 closures are no true closures or is this a bug in my IDE (IDEA 12)?
For some definition of closures (one including mutable local capture),
JDK8 lambdas are not closures (hence, they are not called closures).
AIUI, the main goal of lambdas was to reduce verbosity/overhead of
anonymous classes used with algorithms that better exploit parallelism.
These do not typically require or work well with shared variables, and
supporting mutable locals efficiently would require considerable extra
effort for something substantially beyond the main goal.
I'm sure you can get a more authoritative explanation by checking the
lambda mailing-list archives:
<http://mail.openjdk.java.net/pipermail/lambda-dev/>
I suggest looking for terms such as 'mutable local capture', and
'effectively final'.
--
ss at comp dot lancs dot ac dot uk