Lambdas: local variables need final, instance variables don't

The fundamental difference between a field and a local variable is that the local variable is copied when JVM creates a lambda instance. On the other hand, fields can be changed freely, because the changes to them are propagated to the outside class instance as well (their scope is the whole outside class, as Boris pointed out below).

The easiest way of thinking about anonymous classes, closures and labmdas is from the variable scope perspective; imagine a copy constructor added for all local variables you pass to a closure.


In document of project lambda : State of the Lambda v4

Under Section 7. Variable capture, It is mentioned that....

It is our intent to prohibit capture of mutable local variables. The reason is that idioms like this:

int sum = 0;
list.forEach(e -> { sum += e.size(); });

are fundamentally serial; it is quite difficult to write lambda bodies like this that do not have race conditions. Unless we are willing to enforce—preferably at compile time—that such a function cannot escape its capturing thread, this feature may well cause more trouble than it solves.

Edit :

Another thing to note here is, local variables are passed in constructor of inner class when you access them inside your inner class, and this won't work with non final variable because value of non-final variables can be changed after construction.

While in case of instance variable, compiler passes reference of class and class' reference will be used to access instance variable. So it is not required in case of instance variables.

PS : It is worth mentioning that, anonymous classes can access only final local variables (in JAVA SE 7), while in Java SE 8 you can access effectively final variables also inside lambda as well as inner classes.


In Java 8 in Action book, this situation is explained as:

You may be asking yourself why local variables have these restrictions. First, there’s a key difference in how instance and local variables are implemented behind the scenes. Instance variables are stored on the heap, whereas local variables live on the stack. If a lambda could access the local variable directly and the lambda were used in a thread, then the thread using the lambda could try to access the variable after the thread that allocated the variable had deallocated it. Hence, Java implements access to a free local variable as access to a copy of it rather than access to the original variable. This makes no difference if the local variable is assigned to only once—hence the restriction. Second, this restriction also discourages typical imperative programming patterns (which, as we explain in later chapters, prevent easy parallelization) that mutate an outer variable.