What’s the Real Difference Between Lambdas and Closures in Java?
This article explains the distinct concepts of lambdas and closures, illustrates how Java historically handled closures, shows Python lambda behavior, and discusses the implications of variable capture and finality in Java 8 lambda expressions.
Developers familiar with JavaScript or Ruby often confuse the terms lambda and closure, but they belong to different dimensions of programming concepts.
A closure, as described by Ruby creator Yukihiro Matsumoto, packages a function together with its surrounding variables, extending their lifetime; it is functionally equivalent to object-oriented approaches.
Java supported closures early on, though they were rarely used. An example of a pre‑Java 8 closure is:
public static Supplier<Integer> testClosure(){
final int i = 1;
return new Supplier<Integer>() {
@Override
public Integer get() {
return i;
}
};
}
public interface Supplier<T> {
T get();
}Here the local variable i is captured by the anonymous class, extending its lifetime beyond the method scope.
Languages that support lambda expressions typically also support closures because a lambda resides inside a function and can capture its local variables. In Python, a lambda can be written as:
#!/usr/bin/python
y = 1
f = lambda x: x + y
print f(2) # prints 3
y = 3
print f(2) # prints 5The variable y is an external variable captured by the lambda.
In Java, before Java 8, anonymous classes required captured variables to be declared final to avoid variable‑capture leaks that could cause thread‑safety issues, as noted in "Effective Java" and "Java Concurrency in Practice".
Java 8 introduced lambda syntax, allowing the same capture without explicitly marking variables as final:
public static Supplier<Integer> testClosure() {
int i = 1;
return () -> {
return i;
};
}Although the final keyword is omitted, the compiler treats captured variables as effectively final. Attempting to modify the captured variable results in a compilation error:
public static Supplier<Integer> testClosure() {
int i = 1;
i++;
return () -> {
return i; // compilation error
};
}This illustrates that Java’s lambda implementation enforces finality of captured variables, which some developers find overly restrictive.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
21CTO
21CTO (21CTO.com) offers developers community, training, and services, making it your go‑to learning and service platform.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
