10

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());
            }
       }
   }
QuackDuck
  • 153
  • 1
  • 8
  • 3
    [It is stated](https://stackoverflow.com/questions/34865383/variable-used-in-lambda-expression-should-be-final-or-effectively-final/50341404#50341404), look closer: "*The restriction to effectively final variables prohibits access to dynamically-changing local variables, whose capture would likely introduce concurrency problems.*" – Vince May 21 '18 at 21:42
  • If you run a lambda async the next line will execute with no guarante that is updated by the second thread. The same limitation applies to anonymous objects. Also, there's questions on SO that covers exact your quesiton – Marcos Vasconcelos May 21 '18 at 21:47
  • 3
    **Some of those duplicates are *not* duplicates.** [Answers don't make questions duplicates](https://meta.stackoverflow.com/a/367502/2398375). All those duplicates make the actual answer harder to obtain.. In fact, most of those answers don't even apply to this problem. No wonder people don't care when they ask a question that may have already been answered here - they're forced to filter through a bunch of irrelevant answers to get the answer to their question. – Vince May 21 '18 at 22:05

3 Answers3

17

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

  • 1
    Not only multi-thread programming. The lambda might also outlive the function even in single thread, and then the original variables don't exist anymore. That—and the fact JVM does not support variable references—is why the closure has *copies* of the variables, and can't actually modify the original ones. And making them mutable independently would be confusing, so they must be final. – Jan Hudec Apr 14 '21 at 11:19
3

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.

NocNit
  • 280
  • 1
  • 7
0

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.

noobCoder
  • 292
  • 2
  • 17