0

I just read in a book that when a lambda expression is assigned to a functional interface, then that sets the "target type" for the lambda and an instance of that type (that is, the functional interface's type) is created with the lambda expression used as implementation for the abstract method in the functional interface.

My question: If so, then does that mean lambdas aren't really standalone methods and as such a new type of element brought into the language, but are simply a more compact way for expressing an anonymous class and as such merely are added facility (just like generics) on the compiler's side?

Moreover, how do method references comply with that, in particular, static methods which are not associated with any objects? For example, when a method reference to an instance method is assigned to a functional interface then the encapsulating object for that method is used, but what happens in the case of a static method - those are not associated with any object.. ?

Learnerer
  • 543
  • 1
  • 5
  • 13
  • The JLS [section 15.27](https://docs.oracle.com/javase/specs/jls/se9/html/jls-15.html#jls-15.27) on lambda expressions and [section 15.13](https://docs.oracle.com/javase/specs/jls/se9/html/jls-15.html#jls-15.13) on method references has the answers for you. – Klitos Kyriacou Nov 25 '17 at 12:01

2 Answers2

1

If so, then does that mean lambdas aren't really standalone methods and as such a new type of element brought into the language,

Correct, lambdas are compiled into normal methods with a synthetic name

but are simply a more compact way for expressing an anonymous class and as such merely are added facility (just like generics) on the compiler's side?

No, it's not only on the compiler side. There are is also code in the JVM involved, so that the compiler doesn't have to write class files for the lambdas.

Moreover, how do method references comply with that, in particular, static methods which are not associated with any objects?

Method references are not different from lambdas: at runtime there has to be an object implementing the functional interface. Upon calling the "SAM" of the object this method will call the referenced method.

For example, when a method reference to an instance method is assigned to a functional interface then the encapsulating object for that method is used,

No, it can't be used. Let's take the following example using a System.out::println method reference:

Arrays.asList("A", "B").forEach(System.out::println);

List<E>.forEach() expects a Consumer<? super E> which defines the method void accept(E e). The compiler need to generate byte code and other information in the class file so that at runtime the JVM can generate a class implementing Consumer<E> with a method void accept(E e). This generated method then calls System.out.println(Object o).

The runtime generated class would look something like

class $$lambda$xy implements Consumer<Object> {
    private PrintStream out;

    $$lambda$xy(PrintStream out) {
        this.out = out;
    }

    void accept(Object o) {
        out.println(o);
    }
}

Your question from the comment: "Why not directly assign to instance and its method?"

Let's expand the example a little bit:

static void helloWorld(Consumer<String> consumer) {
    consumer.apply("Hello World!");
}

public static void main(String[] args) {
    helloWorld(System.out::println);
}

To compile this, the compiler has to generate bytecode that creates an object implementing Consumer<String> (so it can pass the object into helloWorld()). That object somehow has to store the information that upon calling it's accept(x) method it has to call println(x) on the System.out PrintStream.

Other languages may have other names or concepts for this kind of objects - in Java the established concept is "an anonymous class implementing the interface and an object of that anonymous class".

How does the object store this information? Well, you could invent some super cool new way to store this information. The Java Language designers decided that an anonymous class would be good enough - for the time being. But they had the foresight that if someone came along with a new idea to implement it in a more efficient way, this should be easy to integrate into the Java ecosystem (Java compiler and JVM).

So they also decided to create that anonymous class not at compile time but to let the compiler just write the necessary information into the class file. Now the JVM can at runtime decide on what the optimal way to store the information (calling the correct method on the correct object) is.

Thomas Kläger
  • 17,754
  • 3
  • 23
  • 34
  • Thanks for the detailed reply. But I'm still having a hard time understanding that: why would "the JVM generate a class implementing Consumer with a method void accept(E e)" when that class with its implementation of the method are going to call the instance (via its actual object) to carry out the contract of the functional interface? Why not directly assign to instance and its method? Do you believe it's because the instance does not decoratively implement the interface? – Learnerer Nov 26 '17 at 10:21
  • @Learnerer I've updated my answer, hopefully this helps – Thomas Kläger Nov 26 '17 at 14:01
  • maybe the confusion is due to interference between the programming model and the implementation mechanisms.. . I appreciate your answer. – Learnerer Nov 29 '17 at 07:02
0

For example, when a method reference to an instance method is assigned to a functional interface then the encapsulating object for that method is used, but what happens in the case of a static method - those are not associated with any object..

That depends on context. Let say we have a static Utils#trim(String) method that will obviously trim given string.

And now, lest have a List<String> list and lets have some strings in it. We can do something like this:

list.stream().map(Utils::trim).collect(Collectors.toList());

As you can see, in given context, we are using lambda static method reference in order to use every string in list as input argument of Utils::trim method.

Antoniossss
  • 31,590
  • 6
  • 57
  • 99
  • Thanks. But I'm really not asking how to use lambdas or method references, I'm just trying to figure out the workings behind the scene - how they're actually implemented – Learnerer Nov 25 '17 at 11:06