GeezerVisonThe World Wide Web, restored to 800 pixels of glory. |
| Home|About|Gaming cabinet|Archives|How it works|Starter sites |
GeezerVison is showing zetcode.com — Variable Capture in Java Lambda Expressions Variable Capture in Java Lambda Expressionslast modified May 25, 2025 This tutorial explores variable capture in Java lambda expressions, a fundamental concept in functional programming with Java. We'll cover the rules and practical examples of how lambdas interact with surrounding variables. Variable capture in lambda expressions refers to the ability of a lambda to use variables declared outside its body. These variables are said to be captured by the lambda. Java has specific rules about which variables can be captured and how they can be used. The most important rule is that any local variable, formal parameter, or exception parameter used but not declared in a lambda must be final or effectively final. This ensures predictable behavior when lambdas are executed, especially in concurrent contexts. An effectively final variable is one whose value is never changed after it is initialized. While not explicitly declared with the final keyword, it can be treated as final because its value remains constant throughout its scope. This rule is crucial because it prevents unexpected behavior when lambdas are executed later, such as in a different thread or after the method has returned. If a lambda could modify a captured variable, it could lead to unpredictable results, especially in concurrent programming scenarios. Capturing Local VariablesThis example demonstrates capturing a local variable in a lambda expression. The variable must be effectively final to be captured. Main.java
void main() {
final String greeting = "Hello";
Runnable r = () -> System.out.println(greeting + " there!");
r.run();
}
Here, the lambda captures the local variable 'greeting' which is explicitly declared as final. The lambda can access this variable when it executes. If we tried to modify greeting after the lambda declaration, it would cause a compilation error. $ java Main.java Hello there! Effectively Final VariablesThis example shows that variables don't need to be explicitly final if they're effectively final. The compiler treats them as final if they're not modified. Main.java
void main() {
int count = 5; // effectively final
Function<Integer, Integer> multiplier = x -> x * count;
System.out.println(multiplier.apply(3));
}
The variable $ java Main.java 15 Instance Variable CaptureLambda expressions can capture instance variables without any restrictions. Unlike local variables, instance variables don't need to be final or effectively final. Main.java
class Example {
private String prefix = "Result: ";
void process() {
Function<Integer, String> formatter = n -> prefix + n;
System.out.println(formatter.apply(42));
}
}
void main() {
new Example().process();
}
The lambda captures the instance variable
Lambdas in Java can freely access and modify instance variables (like
In contrast, local variables are stored on the stack and exist only while the method is executing. To prevent concurrency issues or access to invalid memory, Java requires lambdas to treat local variables as effectively final (unchanged after assignment). When a lambda uses a local variable, Java creates a copy of its value at the time the lambda is defined. This ensures the lambda has a consistent snapshot, even if the original variable's stack frame is destroyed. Modifying the local variable after the lambda's creation would create a mismatch between the copied value and the original, so the compiler enforces immutability to maintain correctness. $ java Main.java Result: 42 Capturing Method ParametersMethod parameters can be captured by lambda expressions if they are effectively final. This example demonstrates capturing a method parameter in a lambda. Main.java
void printFiltered(List<String> list, String word) {
list.stream()
.filter(s -> s.contains(word)) // capturing method parameter
.forEach(System.out::println);
}
void main() {
printFiltered(List.of("apple", "banana", "grape"), "ap");
}
The lambda captures the method parameter $ java Main.java apple grape Attempting to Modify Captured VariableThis example demonstrates what happens when you try to modify a captured variable, which violates the effectively final requirement. Main.java
void main() {
int counter = 0;
// This lambda would cause a compilation error if uncommented
// Runnable incrementer = () -> counter++; // Error
// counter++; // This would make counter not effectively final
Runnable printer = () -> System.out.println("Counter: " + counter);
printer.run();
}
The commented code shows an attempt to modify a captured variable, which would cause a compilation error. The working example only reads the variable, which is allowed as long as the variable remains effectively final. $ java Main.java Counter: 0 Capturing Multiple VariablesLambdas can capture multiple variables from their enclosing scope, as long as all captured variables are effectively final. Main.java
void main() {
String name = "Alice";
int age = 30;
String format = "%s is %d years old";
Supplier<String> info = () -> String.format(format, name, age);
System.out.println(info.get());
}
This lambda captures three variables: name, age, and format. All are effectively final and can be used within the lambda body. The lambda combines these values to create a formatted string. $ java Main.java Alice is 30 years old Capturing in Nested LambdasThis example demonstrates variable capture in nested lambda expressions. The same effectively final rules apply to variables captured by nested lambdas. Main.java
void main() {
final int base = 10;
Function<Integer, Function<Integer, Integer>> adderCreator =
x -> y -> x + y + base; // nested lambda
Function<Integer, Integer> addFive = adderCreator.apply(5);
System.out.println(addFive.apply(3)); // 5 + 3 + 10 = 18
}
The outer lambda captures 'base' and the inner lambda captures $ java Main.java 18 SourceJava Language Specification - Lambda Expressions This tutorial has explored variable capture in Java lambda expressions. We've seen how lambdas can capture local variables, instance variables, and method parameters, with the important restriction that local variables must be effectively final. These rules help ensure predictable behavior in functional programming contexts. AuthorMy name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming. List all Java tutorials. |
| You are visitor 01402503 — GeezerVison does not store the pages you look up. Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required. |