Attempting to reassign a local variable that a lambda expression captures results in a compile-time error, because Java requires captured local variables to be final or effectively final — assigned exactly once and never changed afterward.
Key Points: • "Effectively final" means the variable's value is never reassigned after initialization, even though it's not explicitly marked final. • The compiler enforces this at the point of the reassignment, producing an error like "local variables referenced from a lambda expression must be final or effectively final." • The restriction exists because lambdas may execute later or on a different thread than where they were created, and Java captures local variables by value, not by reference — mutability would create inconsistent or unsafe copies. • Instance fields and static fields don't have this restriction; a lambda can freely read and modify fields of the enclosing object. • A common workaround for accumulating a value across lambda calls is to use a mutable holder like an array, an AtomicInteger, or an instance field instead of a plain local variable.
Example: Writing int count = 0; then list.forEach(x -> count++); inside the lambda body fails to compile, because count++ reassigns count, violating effective finality; using an AtomicInteger instead compiles and works correctly.
Code Example:
int count = 0;
list.forEach(x -> {
// count++; // compile error: count is not effectively final
});
AtomicInteger atomicCount = new AtomicInteger(0);
list.forEach(x -> atomicCount.incrementAndGet());Interview Tip: A concise interview answer is:
"It won't compile — captured local variables have to be final or effectively final, meaning they can only be assigned once. Java captures locals by value, and since a lambda might run later or on another thread, allowing mutation would be unsafe. If I need a running total across lambda invocations, I use a mutable holder like AtomicInteger instead of a plain local variable."