Compiler error for lambda - "Variable should be effectively final" but no error for method reference
已回答
What is also strange
- There is red errors ‘!’ counter in the editor window top
- After pressing ‘F2’, tooltip is about error
- After moving cursor and returning back, tooltip is “Lambda can be replaced with method reference”
// Example:
// Lambda -> compiler error -> variable should be effectively final.
// Method -> no compiler error.
// But both are just different forms of the same.
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
}
}
请先登录再写评论。
Hi Sammesh
Could you please share more configuration details of your environment, for example, are you compiling by Gradel and getting the error as well or you're not using Gradle? Do you get this error performing the next steps:
Which IDE version are you running?
Hi Monica ,
I use IntelliJ IDEA 2025.1.3
The project is pom.xml based.
This code is in Scratch file.
When I run/debug scratch, code is compiled with error with Lambda and is compiled and run successfully with Method Reference.
Hi Sam Mesh,
Thanks for the details. I reviewed the snipped code you added and searched also through our database. Basically, the compiler’s error is correct because the behavior conforms to the Java spec; the IDE’s suggestion is intentional. So it works as intended. Here's the explanation:
The lambda
b1(() -> c1.b())is illegal because c1 is not effectively final; the method referenceb1(c1::b)is legal because it targets the instance captured at invocation time, not at lambda creation time.So the mixed IDE signals (red error counter, F2 shows error, then “Lambda can be replaced with method reference”) come from the inspection layer seeing a method-reference opportunity even though the lambda is invalid in this context. That suggestion doesn’t imply the lambda is valid; it’s suggesting a refactor that would become valid. Then it works as intended from the Java language perspective.
I reproduced the sample using Java 23, Maven and Scratch file:
• Lambda:
b1(() -> c1.b());→ compile error “Variable used in lambda expression should be final or effectively final”.• Method reference:
b1(c1::b);→ compiles and runs.Here's a more detailed explanation of the root cause:
c1is reassigned, so it isn’t effectively final → compile-time error.c1::bis decoded as a function object that, when invoked, callsbon the receiver object captured at the moment the method reference is created. Crucially, the local variablec1itself is not captured by the method reference expression as a mutable variable; instead, the current value ofc1is evaluated and stored as the receiver. That doesn’t requirec1to be effectively final.() -> 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.b1(c1::b);C1 c1 = new C1();Copy into a final variable before the lambda:
final C1 c = c1; b1(() -> c.b());We already have the same case at ticket IDEA-314159, if you want to take a look at it.
Hi Monica ,
Thank you for detailed comments, I need some time to digest that this works as specified in JLS. Will comment later.
Even AI might (by mistake?) say that for method local variable should be effectively final.
About https://youtrack.jetbrains.com/issue/IDEA-314159/Method-Reference-causes-Compiler-Error-while-Lambda-Does-Not - this is different stuff. Method reference correctly isn't compiled because method signature is not what is required - provided method is without parameters but required lambda is with one parameter.