Reputation: 30284
I understand closure and have applied in some language such as Python and SML. Nevertheless, when I read wikipedia about closure in Java (of course, just 8 version), I don't understand difference if Java supports closure or not in their example.
Those code I copy from Wikipedia : Closure
The java code without closure :
class CalculationWindow extends JFrame {
private volatile int result;
...
public void calculateInSeparateThread(final URI uri) {
// The expression "new Runnable() { ... }" is an anonymous class implementing the 'Runnable' interface.
new Thread(
new Runnable() {
void run() {
// It can read final local variables:
calculate(uri);
// It can access private fields of the enclosing class:
result = result + 10;
}
}
).start();
}
}
And if Java supports closure, the code will looks like:
class CalculationWindow extends JFrame {
private volatile int result;
...
public void calculateInSeparateThread(final URI uri) {
// the code () -> { /* code */ } is a closure
new Thread(() -> {
calculate(uri);
result = result + 10;
}).start();
}
}
So, my question is : if Java supports closure, which special thing in second code ? I really don't see main difference between two code.
Please tell me this point.
thanks :)
Upvotes: 9
Views: 813
Reputation: 176
Well, there are mainly two differences. The first one is linked to the underlying process happening in Javac and the JVM, and the second one is the syntax.
Before given an explanation, lets define very quickly what a closure in 'real' functional language is: a function coming along with its lexical environment and memory context.
At first, the compiler will resolve this code by 'scanning' the 'syntaxiq context' in which the code is going to be executed (not the variables, but the code you write cause the compiler does static checks). If it finds that you are writing a lambda as a parameter of a method that is waiting a functional interface, you will be able to compile so that the JVM will be able to find the right piece of code to execute. In fact you are going to implement an interface that exposes only one signature on the fly.
Then, the syntax by itself is important cause it will not give you the same power than an anonymous class where you will be able to implement or override several methods in the same place.
The piece of code in the question is not very relevant to see the difference between the two concepts and it is not using 'closure' in it's whole. Here is a piece of code that could help to see the potential:
public class MyClass
{
// A one method interface.
public static interface Function
{
void execute(int a);
};
// An implementation of Function using the closure and lambda.
public static Function createPrintAddToTenFunction()
{
Integer x = 10;
Function func = (a) -> System.out.println(x + a);
return func;
}
// A basic program.
public static void main(String args[])
{
Function func = createPrintAddToTenFunction();
func.execute(10);
}
}
This compile in java 8 and will print:
20
But, there is something weird in Java with closure. This piece of code is coming from the online documentation, Listing 14:
public static void main(String... args) {
StringBuilder message = new StringBuilder();
Runnable r = () -> System.out.println(message);
message.append("Howdy, ");
message.append("world!");
r.run();
}
This will print
Howdy, world!
And that is just what you don't want in a functional programming language. The JVM does this cause Java is an object oriented language and is pretty good at it.
In Java you use a lot of references to the heap (which are close to pointers in a language like C or the even closer C++). With this principle, you are able to modify a variable initiated in the program's memory context if you have embedded a reference to it in the execution stack. That's the implicit principle coming from the Von Neumann Architecture. This differs from a functional language which should enclose different execution contexts into each other which is subtly different and will ensure you that a value referred by a variable will not be modified by a later assignment of the variable. But that's another story.
Upvotes: 0
Reputation: 8463
The point is that they are not really so different functionally:
() -> {
calculate(uri);
result = result + 10;
}
is equivalent to a new class instance of Runnable with an equivalent implementation of the run() method. You replace a lot of "boiler-plate" code with a simple lambda function.
Using the lambda, your code becomes much more expressive, concise, easier to write, and very readable. And that's just where the benefits start, once you enter the world of closures and lambda functions.
Upvotes: 4
Reputation: 718886
The difference is that:
They achieve the same end, but the lambda syntax is certainly more light-weight.
However, a lambda can only access local variables in the scope in which it is declared if they are final
(or effectively final); see 15.27.2 in JSR-000335 review draft #2. So you could argue that Java lambdas are not full closures.
But the JSR-000335 spec does imply that lambdas are NOT anonymous classes. And this
and super
in a lambda body have a different meaning that they do in a method.
The spec describes lambdas (at one point) as being implemented using "synthetic classes", and states that an instance of the synthetic classes can be reused when appropriate as a compilation optimization. (By contrast, the compiler would not be allowed to make that optimization for an anonymous class.) This optimization means that lambdas are likely to perform better than the equivalent coded using anonymous classes.
Upvotes: 2