Problem
When using a lambda expression in Java, a compilation error "Variable should be effectively final" is encountered. In the editor, a red error '!' counter is shown at the top, and the tooltip shows "Lambda can be replaced with method reference”; while replacing the lambda with a method reference does not result in any error.
Example of code producing this problem:
class C1 {
boolean b() {
return true;
}
static void b1(BooleanSupplier supplier) {}
static void b2() {
C1 c1 = null;
c1 = new C1();
b1(() -> c1.b()); // lambda - compiler error -> variable should be effectively final
b1(c1::b); // method - no compiler error
}
}
Cause
This difference arises because of the fundamental differences between lambda expressions and method references in terms of how they capture and use variables:
-
Lambda expressions capture the local variables at the point the lambda is created. Hence, any local variable referenced by a lambda must be final or effectively final. In this case, reassigning the variable
c1makes it non-effectively final, leading to the compilation error. -
Method references, on the other hand, evaluate the target (like
c1::b), capturing the instance object directly and not the reference variable itself. Therefore,c1does not need to be effectively final.
Why the IDE shows both error and “replace with method reference”:
- The inspection “Lambda can be replaced with method reference” is a structural suggestion that ignores effective-finality constraints. It recognizes that
() -> c1.b()is syntactically convertible toc1::b. In this case the conversion also fixes the compilation error, hence the confusing mix of signals. That’s expected; the compiler’s error is correct, and the quick-fix is a valid way to resolve it.
Resolutions
-
Prefer using method references in such patterns: Replace
b1(() -> c1.b());withb1(c1::b);, which is a valid and compile-able expression. -
Make the variable effectively final: Assign
c1once, such asC1 c1 = new C1();. -
Copy into a final variable before using a lambda expression:
final C1 c = c1; b1(() -> c.b()); -
Restructure the code to avoid capturing a non-final variable in a lambda.
Comments
0 comments
Please sign in to leave a comment.