Are Java 8 lambdas compiled as inner classes, methods or something else? [duplicate]

喜夏-厌秋 提交于 2019-12-28 02:55:06

问题


I have read this article today regarding lambdas:

http://www.infoq.com/articles/Java-8-Lambdas-A-Peek-Under-the-Hood

The article suggests, that lambdas are not implemented as anon inner classes (due to performance). It gives an example that a lambda expression can be compiled as a (static) method of class.

I have tried a very simple snippet:

private void run() {
    System.out.println(this);
    giveHello(System.out::println);
}

private void giveHello(Consumer<String> consumer) {
    System.out.println(consumer);
    consumer.accept("hello");
}

and the output is :

sample.Main@14ae5a5
sample.Main$$Lambda$1/168423058@4a574795
hello

So it's not the same instance. It's not some central "Lambda Factory" instance either..

How are lambdas implemented then?


回答1:


The expression itself, assuming you pass an actual lambda expression and not a method reference, is compiled as a separate, synthetic method. In addition to any formal arguments to the expected functional interface (e.g., a single String in the case of Consumer<String>), it will include arguments for any captured values.

At the code location where a lambda expression or method reference appears, an invokedynamic instruction is emitted. The first time this instruction is hit, a call is made into a bootstrap method on LambdaMetafactory. This bootstrap method will fix up an actual implementation of the target functional interface which delegates to the target method, and this is what gets returned. The target method is either the synthetic method representing the lambda body or whichever named method was provided using the :: operator. While a class that implements the functional interface is being created, the process is deferred; it does not happen at compile time.

Finally, the runtime patches the invokedynamic site with the bootstrap result1, which is effectively a constructor call to the generated delegate with any captured values passed in, including (possibly) an invocation target2. This alleviates the performance hit by removing the bootstrapping process for subsequent calls.


1 See java.lang.invoke end of chapter "timing of linkage", courtesy of @Holger.

2 In the case of a lambda which no captures, the invokedynamic instruction will usually resolve to a shared delegate instance that can be reused during subsequent calls, though this is an implementation detail.




回答2:


I asked myself the same question and found this video, a talk by Brian Goetz. It is very useful introduction to how lambdas are implemented in java.

Edit (summary): Watched it a while back, so this might not be completely correct. When the files are compiled, the compiler leaves a description of what the lambda should do. The JRE, then when running the code, will then decide how to implement the lambda. There are several options, inline, method reference, anonymous class. It will then use dynamic allocation to allocate the implementation.




回答3:


Lambda's in Java 8 are so called functional interfaces, that is, anonymous interfaces with one default method.




回答4:


I'm not sure of it but i believe, that it is just compiling to Anonymous inner class. Consumer<T> is an interface, so i would say that your example is almost equals to

    giveHello(new Consumer<String>() {

        @Override
        public void accept(String t) {
            System.out.println(t);
        }
    });

EDIT

after some research, above answer is not complete and valid. Lambda expressions might be translated to anonymous inner class, but don't have to (and they usually don't).



来源:https://stackoverflow.com/questions/26257266/are-java-8-lambdas-compiled-as-inner-classes-methods-or-something-else

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!