Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does lambda translation need generation of a static method?

Lambda translation is a two step process, One: desugaring the lambda into a static method in same class.

public class Main {
    public static void main(String[] args) {
        Runnable r = () -> System.out.println("Hello");
        System.out.println(Arrays.asList(Main.class.getDeclaredMethods()));
    }
}

[private static void Main.lambda$main$0(), public static void Main.main(java.lang.String[])]

Two: generation of a class that implements the Functional Interface.

System.out.println("A class has been generated: " + r.getClass());
System.out.println("That implements a Functional Interface: " + Arrays.asList(r.getClass().getInterfaces()));

A class has been generated: class Main$$Lambda$1/149928006

That implements a Functional Interface: [interface java.lang.Runnable]

Question: What is the need of this static method? Why can't the lambda body be put directly into the interface method? Something like:

class Main$$Lambda$1 {
    public void run() {
        /* Lambda body here */
    }
}
like image 846
Kshitiz Sharma Avatar asked May 03 '15 13:05

Kshitiz Sharma


2 Answers

In addition to the correct answers given here (because the current scheme is more efficient, reducing capture/linkage costs for lambdas and reducing code duplication), there are a few other reasons why your idea simply doesn't make sense.

  • Where would the bytecode come from in the first place? The lambda proxy class is generated at runtime, not compile time. If we were to stuff the bytecode into the proxy class, it would have to come from somewhere. That would mean we'd have to put it into the capturing class file and then copy it into the proxy class. Here, it just lives in the capturing class and we're done.
  • Access control. What if the lambda body calls a private method? By desugaring it into the capturing class, it automatically acquires the access control context of the capturing class (which it is logically a part of.) If we put the bytecode in the proxy class, we'd have to do additional magic to give it the right access control context.
like image 69
Brian Goetz Avatar answered Oct 04 '22 13:10

Brian Goetz


Because this way it's actually cheaper. Generating a lambda from the method on the fly during the first invocation is better than loading a separate class via class loader. Internally it uses UNSAFE.defineAnonymousClass which is more light-weight class than normal. Such "lambda-class" is not bound to any class loader, so can be easily garbage-collected when it's no longer necessary. Also I guess there are plans to make this mechanism even more light-weight and faster. For normal anonymous class this would not be possible as from the point of JVM such classes don't differ from usual classes and much more heavy.

like image 40
Tagir Valeev Avatar answered Oct 04 '22 12:10

Tagir Valeev