In Java, especially when dealing with lambda expressions, anonymous classes, or inner classes, the concept of variable capture and effectively final variables becomes very important.
What is Variable Capture?
Variable capture refers to the process where a lambda expression or inner class accesses variables from the enclosing scope (usually local variables from a method). These variables are said to be “captured” by the lambda or class.
public class VariableCaptureExample {
public static void main(String[] args) {
int number = 10; // This variable is captured
Runnable runnable = () -> {
System.out.println("Captured number: " + number);
};
runnable.run();
}
}
//Here, the lambda expression captures the local variable number.
Code language: JavaScript (javascript)
The Rule: Variables Must Be Effectively Final
Captured variables must be “effectively final”. That means:
The variable is not declared as
final
, but its value never changes after it is assigned.
Why is this required?
Captured variables are accessed from a different thread or context, so to ensure thread safety and predictable behavior, Java restricts them to be effectively final.
What is an Effectively Final Variable?
A variable is effectively final if it is assigned only once and not modified afterward.
Example:Valid (Effectively Final):
public class EffectivelyFinalExample {
public static void main(String[] args) {
String message = "Hello"; // not declared final, but not reassigned
Runnable r = () -> System.out.println(message); // Allowed
r.run();
}
}
Code language: JavaScript (javascript)
Example:Invalid (Not Effectively Final):
public class NotEffectivelyFinal {
public static void main(String[] args) {
String message = "Hello";
message = "Hi"; // reassigned, no longer effectively final
Runnable r = () -> System.out.println(message); // Compile-time error
r.run();
}
}
Code language: JavaScript (javascript)
Where is This Rule Enforced?
This effectively final rule is enforced in:
-
Lambda expressions
-
Anonymous inner classes
-
Local inner classes
It is not required for instance variables or static variables.
Understanding variable capture and effectively final variables is essential when working with lambdas, anonymous inner classes, or local classes in Java. These features enable concise and expressive code but come with the constraint that any local variables they access must be effectively final. This ensures safety, especially in multi-threaded contexts, and simplifies the implementation of closures.