Lambda表达式中变量为何必须是final或有效final?
First, let's look at your code example that triggers the compile error:
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()); } } }
You know removing i fixes the issue, but let's break down why Java enforces this rule for lambdas:
Avoid unpredictable results in concurrent code: Lambdas are frequently used in async/parallel scenarios (like your ExecutorService example), where the lambda might run long after the surrounding code has moved on. If non-final variables were allowed, their values could change before the lambda executes. In your loop,
iincrements every iteration—if the lambda could access it directly, by the time the thread runs,imight already be 20 (or some other unexpected value), leading to inconsistent outputs.Maintain consistency with anonymous inner classes: Before lambdas arrived in Java 8, anonymous inner classes already required accessed local variables to be final or effectively final. This rule carries over to lambdas to keep the language consistent, so developers don't have to learn conflicting rules for similar functionality.
Simplify compiler logic and prevent race conditions: When a lambda captures a variable, the compiler needs to manage how that variable is accessed. If the variable is final or effectively final, the compiler can safely copy its value into the lambda's closure without worrying about future modifications. Allowing mutable variables would force the compiler to handle synchronization and memory visibility issues, adding unnecessary complexity and opening the door to hard-to-debug race conditions.
As an alternative fix besides removing i, you can capture a local effectively final copy of i inside the loop:
for (int i = 0; i < 20; i++) { int currentNum = i; // This is effectively final futureLists.add(executorService.submit(() -> "Hello world" + currentNum)); }
内容的提问来源于stack exchange,提问作者QuackDuck

