Java 8是否支持闭包?

我很困惑。 我认为Java8会从石器时代出现,并开始支持lambdas /封闭。 但是当我尝试:

public static void main(String[] args) { int number = 5; ObjectCallback callback = () -> { return (number = number + 1); }; Object result = callback.Callback(); System.out.println(result); } 

它说这个number should be effectively final 。 那是呃,不是我想的封闭。 这听起来像是在复制环境的价值,而不是参考。

奖金的问题!

Android会支持Java-8的function吗?

为什么哦,为什么,Java。 为什么哦为什么。

您需要与相关的Oracle Java团队成员进行长时间的(私人)讨论才能得到真正的答案。 (如果他们愿意跟你说话…)


但是我怀疑它是向后兼容和项目资源约束的结合。 事实上,从现实的angular度来看,目前的做法“足够好”。

实现过程上下文作为第一类对象(即闭包)需要某些局部variables的生存期超出了声明方法调用的返回。 这意味着你不能把它们放在堆栈上。 相反,最终会出现一些局部variables必须是堆对象的字段的情况。 这意味着您需要一种新的隐藏类或对JVM体系结构进行根本性更改。

虽然在技术上实现这种事情是可能的,但是Java语言并不是一种“绿色领域”语言。 需要支持“真正closures”的自然变化将是困难的:

  • Oracle和第三方实施者需要花费大量精力来更新所有的工具链。 (而且我们不只是在谈论编译器,还有debugging器,分析器,混淆器,字节码工程框架,持久性框架…)

  • 那么存在这样的风险:这些变化中的一些会影响到数百万现有的已部署Java应用程序的向后兼容性。

  • 其他语言有潜在的影响,以某种方式利用JVM。 例如,Android依赖于JVM体系结构/字节码文件作为其Davlik工具链的“input语言”。 Python,Ruby以及代码为JVM平台生成的各种函数式语言都有语言实现。


简而言之,Java中的“真正closures”将成为所有相关人员的一个非常可怕的主张。 “closures总决赛”破解是一个务实的妥协,确实有效,在实践中已经足够了。

最后,在未来的版本中总有可能会取消final限制。 (虽然我不会屏住呼吸……)


Android会支持Java-8的function吗?

除非有可靠的内部知识,否则这是不可能的。 如果他们这样做,他们会疯狂的在这里揭示它。 当然谷歌还没有宣布支持Java 8。

但好消息是,现在KitKat和Android Studio或Eclipse ADT的相应版本支持Java 7语法扩展。

你将不得不说明你的“封闭”的定义。

对我来说,“闭包”是一个东西(一个函数或对象或其他东西,可以以某种方式运行,像拥有方法)捕获(“closures”)一个局部variables从它的封闭范围,并可以使用该variables在其代码中,即使函数或对象的方法稍后运行,包括封闭范围不再存在时。 在不同的语言中,可以通过值,或通过引用,或两者来捕获variables。

通过这个定义,Java匿名类(自Java 1.1以来就已经存在) 闭包,因为它们可以从其封闭范围引用局部variables。

Java 8中的Lambdas基本上是一个匿名类的特殊情况(即一个匿名类,它只用一个方法实现一个接口(一个“function接口”),它没有实例variables,并且不引用它自己this明确或暗示))。 任何lambda都可以重写成一个等价的匿名类expression式。 所以上面所说的也适用于lambda。

那是呃,不是我想的封闭。

那么,先生,有一个“closures”的定义。

我觉得final限制有技术上的原因。 lambdaexpression式只是从周围的方法上下文中获取值,因为引用位于堆栈上,并且不会在方法的结束后继续存在。

如果将上下文的值放入引用中,可以构build一个“真正的”闭包:

 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. 

您可以采用任何合适的任何对象的实例,而不是一个数组,因为它存在于堆中,只有对这个实例的引用保持(最终)在lambdaexpression式中。

在这种情况下, container的值被包含在mutterfunktion 。 每次调用mutterfunktion都会创build一个新的引用实例。

该值不能从函数外部访问(这在Java 7和以前很难创build)。 由于lambdaexpression式是作为方法引用实现的,因此在此示例中没有涉及内部类。

你也可以在方法的上下文中定义container ,你可以在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. 

所以你的问题的答案是“是”。

你可以使用最终的引用来解决在外层作用域中声明的variables的变化状态,但是结果保持不变,封闭层外层作用域的状态不被保留,并且引用(通过最后的引用)对象的进一步变化是在closures看到。

 @Test public void clojureStateSnapshotTest() { Function wrapperFunc; wrapperFunc = (a) -> { // final reference final WrapLong outerScopeState = new WrapLong(); outerScopeState.aLong = System.currentTimeMillis(); System.out.println("outer scope state BEFORE: " + outerScopeState.aLong); Function closure = (b) -> { System.out.println("closure: " + outerScopeState.aLong); return b; }; outerScopeState.aLong = System.currentTimeMillis(); System.out.println("outer scope state AFTER: " + outerScopeState.aLong); // show correct snapshot state closure.apply(new Object()); return a; }; // init clojure wrapperFunc.apply(new Object()); } public class WrapLong { public long aLong = 0; } 

但还是很有趣…