Lambdas can access variables from three main places:
1. ✅ Parameters passed to the lambda
Just like any method, a lambda has its own parameters.
(x, y) -> x + y // `x` and `y` are lambda parameters
2. ✅ Local variables from the enclosing scope — but only if they are effectively final
This is a key concept.
🧠 “Effectively final” means: the variable is not modified after it’s initialized, even if it’s not explicitly marked as
final
.
Example (valid):
int base = 10; // effectively final
Function<Integer, Integer> addBase = x -> x + base;
Example (invalid):
int base = 10;
base = 15; // ❌ now it's not "effectively final"
Function<Integer, Integer> addBase = x -> x + base; // Compile error
The reason: lambdas do not capture variables by reference, they capture the value of the variable at the time of lambda creation.
3. ✅ Instance and static variables
Lambdas can freely access instance variables (this.var
) and static variables of the enclosing class.
Example:
class Calculator {
int offset = 100;
Function<Integer, Integer> addOffset() {
return x -> x + offset; // accessing instance variable
}
}
🔒 Summary Table
Variable Type | Can Lambda Access? | Notes |
---|---|---|
Lambda Parameters | ✅ | Standard parameters |
Local Variables | ✅ if effectively final | Cannot be modified after declaration |
Instance Variables | ✅ | No restrictions |
Static Variables | ✅ | No restrictions |
🧠 Why “effectively final”?
Java needs this restriction to:
- Ensure thread safety (lambda can be executed later in a different thread).
- Avoid mutable state confusion.
- Maintain consistency with how anonymous inner classes behave.