Pages

Thursday, December 1, 2016

What is a Java Lambda Expression?

A lambda expression is a shortcut notation for an anonymous class implementation of an interface.


Which Interface? Where is the Type Definition...?

A lambda expression is used in the context of a target method signature. For example the following method signature

     public String doSomething(String s, MyInterface mi){...}

could be invoked with the following code using an anonymous class:

     doSomething("hello", new MyInterface(){
          public void myMethod() { 
               System.out.println("goodbye");}
          });

it can also be invoked with the following lambda expression:

     doSomething("hello", ()->{ System.out.println("goodbye");});



The target method doSomething is expecting two parameters - a String and an instance of MyInterface. The String value is clearly "hello", but the other is not so obvious. What happens here is the compiler sees that an instance of MyInterface needs to be somehow created from this expression and passed as the second parameter:

     ()->{ System.out.println("goodbye");}

To understand how this takes place we need to look at MyInterface

     interface MyInterface {
          public void myMethod();
     }


So what's so special about that interface?

The key characteristic of this interface is that it contains exactly one method definition. This makes it a functional interface, and it could be annotated with @FunctionalInterface for clarity although this is not necessary. Lamba expressions only work with functional interfaces.

Since the compiler needs to create an instance of MyInterface which it can pass to doSomething, it needs an implementation of myMethod.


Where is the compiler going to find an implementation of myMethod?

This is where the lambda expression comes into the picture. A lambda is a shortened syntax for an anonymous class definition, but since the interface contains only one method definition, the compiler can easily fill in the blanks. The left side of the lambda expression is a placeholder for the interface method signature parameters. Without this left side, the implementation would have no point of reference for these parameters.

For example if we change the signature to

     interface MyInterface {
          public void myMethod(int myNum);
     }

Then our lambda would look like this

     (i)->{ System.out.println("goodbye");}

Note that the simple implementation doesn't use the int value (which is ok).


Recap

Take an anonymous class implementation, strike out the unnecessary syntax which the compiler can figure out because there's only one method in the interface, then add a -> 

     doSomething("hello", new MyInterface(){
          public void myMethod()->
               System.out.println("goodbye");}
          });

What's left is a lambda expression!