I think the final
restriction has technical reasons. A lambda expression simply takes the value from the surrounding method context because the reference lives on the stack and will not survive the finishing of the method.
If you put the context's value into a reference, you can build a "real" closure:
import java.util.function.Supplier;
public class CreatingAClosure {
public static void main(String[] args) {
Supplier<Supplier<String>> mutterfunktion = () -> {
int container[] = {0};
return () -> {
container[0]++;
return "Ich esse " + container[0] + " Kuchen.";
};
};
Supplier<String> essen = mutterfunktion.get();
System.out.println(essen.get());
System.out.println(essen.get());
System.out.println(essen.get());
}
}
Ausgabe:
Ich esse 1 Kuchen.
Ich esse 2 Kuchen.
Ich esse 3 Kuchen.
Instead of an array you can take any suitable instance of any object, because it lives on the heap and only the reference to this instance is kept (final) in the lambda expression.
In this case the value of container
is enclosed into mutterfunktion
. Every call to mutterfunktion
creates a new referenced instance.
The value is not accessible from outside the function (which was very hard to build in Java 7 and before). Because of lambda expressions are implemented as method references, there are no inner classes involved in this example.
You could also define container
in the method's context an you will be able to do changes outside the lambda:
public static void main(String[] args) {
int container[] = {0};
Supplier<String> essen = () -> {
container[0]++;
return "Ich esse " + container[0] + " Kuchen.";
};
System.out.println(essen.get());
System.out.println(essen.get());
container[0]++;
System.out.println(essen.get());
}
Ausgabe:
Ich esse 1 Kuchen.
Ich esse 2 Kuchen.
Ich esse 4 Kuchen.
So the answer to your question will be "yes".
Java 8 is supporting lambdas not closures
. Sure it does - in about the same sense as Java supports generics. See the accepted answer. – Bywoods