Why does variables in lambdas have to be final or

2019-01-25 17:10发布

问题:

This question already has an answer here:

  • Why are only final variables accessible in anonymous class? 13 answers
  • Why is the “Variable used in Lambda expression must be final or effectively final” warning ignored for instance variables [duplicate] 2 answers
  • Lambdas: local variables need final, instance variables don't 9 answers

When I am writing this code I am getting a compile time error which says: 'Variables in lambdas must be final or effectively final'.

Now, I get this that removing the i from the line :

futureLists.add(executorService.submit( () -> "Hello world" + i));

solves the issue.

But I want to know that why does such a requirement exist?

As per the JLS, all it says is :

Any local variable, formal parameter, or exception parameter used but not declared in a lambda expression must either be declared final or be effectively final, or a compile-time error occurs where the use is attempted.

But it does not state, why such a requirement exist. But why did Java engineers enforce such a requirement for lambdas?

public class test {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
         ExecutorService executorService = Executors.newFixedThreadPool(10);

         List<Future<String>> futureLists = new ArrayList<>();

         for (int i = 0; i < 20; i++) {
             futureLists.add(executorService.submit( () -> "Hello world" + i));
             }

         for (Future<String> itr:futureLists) {
             System.out.println(itr.get());
            }
       }
   }

回答1:

It is related to multi-thread programming.

Local variables in Java have until now been immune to race conditions and visibility problems because they are accessible only to the thread executing the method in which they are declared. But a lambda can be passed from the thread that created it to a different thread, and that immunity would therefore be lost if the lambda, evaluated by the second thread, were given the ability to mutate local variables. - Source



回答2:

The likely reason the Java engineers did this, was to make Java code more durable. When one would allow the variable to be non-final, it's value could be modified from virtually anywhere in the program. This could potentially cause concurrency problems.

It is mentioned in this document:

The restriction to effectively final variables prohibits access to dynamically-changing local variables, whose capture would likely introduce concurrency problems. Compared to the final restriction, it reduces the clerical burden on programmers.



回答3:

Immutable things are easy to distribute. Multiple consumers can use them without having to worry about someone else might have changed the value. Lambda functions in Java are taking Java in the realm of functional programming where you can pass the function around. This is very useful in distributed programming. Since there can be multiple processors it is better to pass final values than adding overhead of concurrency management.