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; }
但还是很有趣…