Java 8是否支持闭包?

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

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功能吗?


为什么哦,为什么,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语法扩展。


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

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

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

    Java 8中的Lambdas基本上是一个匿名类的特例(即一个匿名类,它只用一个方法实现一个接口(一个“功能接口”),它没有实例变量,并且不引用它自己(使用this明确或隐含))。 任何lambda都可以重写成一个等效的匿名类表达式。 所以上面说的也适用于lambda。

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

    那么,先生,你有一个“封闭”的定义。


    我认为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.
    

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

    链接地址: http://www.djcxy.com/p/51283.html

    上一篇: Does Java 8 Support Closures?

    下一篇: Does Go have lambda expressions or anything similar?