Does Java 8 Support Closures?

I'm confused. I thought Java8 was going to emerge from the stone age and start supporting lambdas / closures. But when I try:

public static void main(String[] args) {
    int number = 5;

    ObjectCallback callback = () -> {
        return (number = number + 1);
    };

    Object result = callback.Callback();
    System.out.println(result);
}

it says that number should be effectively final . That's uh, not a closure I think. That just sounds like it's copying the environment by value, rather than by reference.

Bonus question!

Will android support Java-8 features?


Why oh why, Java. Why oh why.

You would need to hold a long (private) discussion with the relevant Oracle Java team members for the true answer. (If they would be willing to talk to you ...)


But I suspect it is a combination of backwards compatibility and project resourcing constraints. And the fact that the current approach is "good enough" from a pragmatic perspective.

Implementing procedure contexts as first-class objects (ie closures) requires that the lifetime of certain local variables extends beyond the return of the declaring method call. That means that you cannot just put them on the stack. Instead you end up with a situation where some local variables have to be fields of an heap object. That means you need a new kind of hidden class OR fundamental changes to the JVM architecture.

While it is technically possible to implement this kind of thing, the Java language is not a "green field" language. A change of the nature need to support "real closures" would be difficult:

  • It would take a huge amount of effort from Oracle and 3rd party implementors to update all of the tool chains. (And we are not just talking about compilers. There are debuggers, profilers, obfuscators, bytecode engineering frameworks, persistence frameworks ...)

  • Then there is the risk that some of these changes would impact on backwards compatibility for the millions of existing deployed Java applications out there.

  • There is the potential impact on other languages, etc that leverage the JVM in some way. For example, Android depends on the JVM architecture / bytecode files as the "input language" for its Davlik tool-chain. There are language implementations for Python, Ruby and various functional languages that code generate for the JVM platform.


  • In short "real closures" in Java would be a big scary proposition for everyone concerned. The "closures for finals" hack is a pragmatic compromise that does work, and that is good enough in practice.

    Lastly, there is always the possibility that the final restriction could be removed in a future edition. (I wouldn't hold my breath though ....)


    Will android support Java-8 features?

    That is impossible to answer unless someone has credible inside knowledge. And if they did, they would be crazy to reveal it here. Certainly Google have not announced support for Java 8.

    But the good news is that Java 7 syntax extensions are now supported with KitKat and corresponding versions of Android Studio or Eclipse ADT.


    You will have to state your definition of "closure".

    To me, a "closure" is something (a function or object or other thing that can be run in some way like having methods) that captures ("closes over") a local variable from its enclosing scope, and which can use that variable in its code, even when the function or object's method is run at a later time, including when the enclosing scope no longer exists. In different languages, it may be possible to capture a variable by value, or by reference, or both.

    By this definition, Java anonymous classes (which have been there since Java 1.1) are closures, since they can refer to local variables from its enclosing scope.

    Lambdas in Java 8 are basically a special case of anonymous classes (namely, an anonymous class which implements an interface with exactly one method (a "functional interface"), and which has no instance variables, and which does not refer to itself (using this explicitly or implicitly)). Any lambda can be re-written into an equivalent anonymous class expression. So what is said above also apply to lambdas.

    That's uh, not a closure I think.

    Well, you sir, have a messed up definition of "closure".


    I think the final restriction has technical reasons. A lambda expression simply takes the value from the surrounding method context because the reference lives on the stack and will not survive the finishing of the method.

    If you put the context's value into a reference, you can build a "real" closure:

    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.
    

    Instead of an array you can take any suitable instance of any object, because it lives on the heap and only the reference to this instance is kept (final) in the lambda expression.

    In this case the value of container is enclosed into mutterfunktion . Every call to mutterfunktion creates a new referenced instance.

    The value is not accessible from outside the function (which was very hard to build in Java 7 and before). Because of lambda expressions are implemented as method references, there are no inner classes involved in this example.

    You could also define container in the method's context an you will be able to do changes outside the 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.
    

    So the answer to your question will be "yes".

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

    上一篇: Java Lambdas和闭包

    下一篇: Java 8是否支持闭包?