我很困惑。我认为Java8将从石器时代开始出现并开始支持lambda / closures。但是当我尝试:
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功能吗?
答案 0 :(得分:40)
为什么哦为什么,Java。为什么哦为什么。
您需要与相关的Oracle Java团队成员进行长时间(私人)讨论,以获得真正的答案。 (如果他们愿意和你谈谈......)
但我怀疑它是向后兼容性和项目资源约束的组合。事实上,从务实的角度来看,目前的方法“足够好”。
将过程上下文实现为第一类对象(即闭包)要求某些局部变量的生命周期超出声明方法调用的返回值。这意味着你不能只把它们放在堆栈上。相反,您最终会遇到某些局部变量必须是堆对象的字段的情况。这意味着您需要一种新的隐藏类或对JVM体系结构的基本更改。
虽然技术上可以实现这种功能,但Java语言不是“绿色领域”语言。改变支持“真正关闭”的性质需要很难:
Oracle和第三方实现者需要花费大量精力来更新所有工具链。 (我们不只是讨论编译器。有调试器,分析器,混淆器,字节码工程框架,持久性框架......)
然后存在这些变化中的一些会影响数百万现有已部署的Java应用程序的向后兼容性的风险。
以某种方式利用JVM对其他语言等产生潜在影响。例如,Android依赖于JVM架构/字节码文件作为其Davlik工具链的“输入语言”。有Python,Ruby和各种函数语言的语言实现,这些语言为JVM平台生成代码。
简而言之,Java中的“真正关闭”对所有相关人员来说都是一个非常可怕的命题。 “决赛关闭”黑客攻击是一种务实的妥协,确实有效,而且在实践中已经足够好了。
最后,在将来的版本中可能会删除final
限制。 (虽然我不会屏住呼吸......)
android会支持Java-8功能吗?
除非有可靠的内部知识,否则无法回答。如果他们这样做,他们会疯狂地在这里透露它。当然谷歌还没有宣布支持Java 8。
但好消息是KitKat及相应版本的Android Studio或Eclipse ADT现在支持Java 7语法扩展。
答案 1 :(得分:13)
你必须陈述你对“封闭”的定义。
对我来说,“闭包”是某种东西(一种能够以某种方式运行的函数或对象或其他东西,比如有方法)从其封闭范围捕获(“封闭”)局部变量,并且可以即使函数或对象的方法稍后运行,包括当封闭范围不再存在时,也要在其代码中使用该变量。在不同的语言中,可以通过值或引用或两者来捕获变量。
根据这个定义,Java匿名类(自Java 1.1以来一直存在)是闭包,因为它们可以从其封闭范围引用局部变量。
Java 8中的Lambda基本上是匿名类的一个特例(即,一个匿名类,它实现了一个只有一个方法的接口(一个“功能接口”),并且没有实例变量,并且没有引用本身(明确或隐含地使用this
))。任何lambda都可以重写为等效的匿名类表达式。所以上面所说的也适用于lambdas。
那是呃,不是我认为的封闭。
嗯,你先生,对“封闭”有一个混乱的定义。
答案 2 :(得分:11)
我认为final
限制有技术原因。 lambda表达式只是从周围的方法上下文中获取值,因为引用存在于堆栈中,并且不会在方法完成后继续存在。
如果您将上下文的值放入引用,则可以构建“真正的”闭包:
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.
您可以使用任何对象的任何合适的实例来代替数组,因为它存在于堆上,并且只在lambda表达式中保留(最终)对此实例的引用。
在这种情况下,container
的值会包含在mutterfunktion
中。每次调用mutterfunktion
都会创建一个新引用的实例。
无法从函数外部访问该值(在Java 7及之前很难构建)。由于lambda表达式是作为方法引用实现的,因此本示例中没有涉及内部类。
您还可以在方法的上下文中定义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.
因此,您的问题的答案将是“是”。
答案 3 :(得分:1)
您可以使用最终引用来改变在外部作用域中声明的变量状态,但结果保持不变,不保留闭包外部作用域的状态以及对引用的对象的进一步更改(通过最终参考文献见封闭。
@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;
}
但仍然很有趣......
答案 4 :(得分:-1)
闭包被认为是不满足函数式编程中纯函数限制的副作用