我理解闭包并且已经应用了Python和SML等语言。然而,当我阅读维基百科关于Java中的闭包(当然,只有8个版本)时,如果Java在他们的示例中支持闭包,我不明白区别。
我从维基百科复制的代码:Closure
没有闭包的java代码:
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();
}
}
如果Java支持闭包,代码将如下所示:
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();
}
}
所以,我的问题是:如果Java支持关闭,第二个代码中哪个特殊的东西?我真的没有看到两个代码之间的主要区别。
请告诉我这一点。
谢谢:)
答案 0 :(得分:4)
关键在于它们在功能上并没有那么不同:
() -> {
calculate(uri);
result = result + 10;
}
等同于 Runnable 的新类实例,其具有 run()方法的等效实现。您可以使用简单的 lambda 函数替换大量的“样板”代码。
使用lambda,您的代码变得更具表现力,简洁,易于编写且易读。一旦你进入了闭包和lambda函数的世界,这就是好处的开始。
答案 1 :(得分:2)
区别在于:
他们达到了同样的目的,但lambda语法肯定更轻量级。
但是,lambda只能访问声明它的范围内的局部变量final
(或实际上是最终的);见JSR-000335审查草案#2中的15.27.2。所以你可以说Java lambda不是完全闭包。
但JSR-000335规范确实暗示lambdas不是匿名类。 lambda体中的this
和super
具有与方法不同的含义。
规范将lambdas(在某一点上)描述为使用“合成类”实现,并声明合成类的实例可以在适当时作为编译优化重用。 (相比之下,编译器不允许对匿名类进行优化。)此优化意味着lambdas 可能的性能优于使用匿名类的等效编码。
答案 2 :(得分:0)
嗯,主要有两个不同之处。第一个链接到Javac和JVM中发生的底层进程,第二个是语法。
在给出解释之前,我们可以非常快速地定义“真实”中的封闭内容。函数式语言是:一个与其词汇环境和记忆环境相关的函数。
首先,编译器将通过扫描'来解析此代码。 ' syntaxiq context'其中将执行代码(不是变量,但是您编写的代码会导致编译器执行静态检查)。如果它发现您正在编写lambda作为等待函数接口的方法的参数,那么您将能够进行编译,以便JVM能够找到要执行的正确代码段。实际上,您将实现一个只能动态显示一个签名的界面。
然后,语法本身很重要,因为它不会给你提供与匿名类相同的能力,你可以在同一个地方实现或覆盖多个方法。
问题中的一段代码与查看两个概念之间的区别并不是很相关,而且它并没有使用' closure'在它的整体。以下是一段有助于发现潜力的代码:
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);
}
}
这在java 8中编译并将打印:
20
但是,关闭时Java中有一些奇怪的东西。这段代码来自online documentation,清单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();
}
这将打印
Howdy, world!
这就是你在函数式编程语言中不想要的东西。 JVM就是这样做的,因为Java是一种面向对象的语言,并且非常擅长。
在Java中,您使用了很多对堆的引用(它们接近于像C这样的语言或更接近C ++的指针)。根据这个原则,如果在执行堆栈中嵌入了对它的引用,则可以修改在程序的内存上下文中启动的变量。这是来自Von Neumann Architecture的隐含原则。这与功能语言不同,功能语言应该将不同的执行上下文彼此包含在一起,这种语言略有不同,并且将确保变量引用的值不会被后来的变量赋值修改。但这是另一个故事。