Lambda expressions

JEP: https://openjdk.java.net/projects/jdk8/features#126

Probably one of the most interesting features of Java 8 are the Lambda expressions. Since some of the other Java 8 features are built on top of Lambda expressions, lets discuss them first.

A Lambda expression is an anonymous function, that is (similar to anonymous inner classes) it does not have a name. Nevertheless, it can be assigned to a reference variable. A Lambda expression can take any number of parameters, contains a statement block which can process the parameters, and optionally returns a result.

Syntax of the Lambda expression

The general syntax of a Lambda expression is

(p1, p2, ...) -> { body; }

Inside the parantheses, the parameters are defined which the function takes. Inside the braces, the statements are implemented which are processing the parameters. If the function returns a value, it can do so through the usual return statement. There are also some special cases:

  • If the function does only take one parameter, the parantheses can be omitted.
  • If the code block contains a single statement only, the braces can be omitted. In that case, also the return statement can be omitted – the result of the anonymous function is then the result of the single statement.
  • If the function does not take any parameters, the parameter list consists of an empty pair of parantheses.

Some examples:

() -> 42;         // returns 42
p -> p + 42;    // returns the value passed as parameter plus 42
(p1, p2, p3) -> { Float sum = p1 + p2 + p3;  return sum / 3.0F; };  // returns the average of three values

Functional interfaces

As said before, a Lambda expression can be assigned to a reference variable to be called later. But, the question is: what is the type of this reference variable? Obviously, it need to consider that a Lambda expression might take any number of parameters, and also might return a value or not. The solution is called functional interface. That is simply an interface definition containing a method called apply() which defines the parameters and their types for the Lambda expression. For example, for the last expression above which calculates the average of three values, we can define the corresponding functional interface like

interface ThreeParamsWithReturn<T, U, V, R> {
   R apply(T t, U u, V v);
}

By using a generic interface, we can also use any type when calling the Lambda expression. We can now create a reference variable and assign the Lambda expression to it:

ThreeParamsWithReturn<Float, Float, Float, Float> func = (p1, p2, p3) -> { Float sum = p1 + p2 + p3;  return sum / 3.0F; };
System.err.println(func.apply(1.0F, 5.0F, 7.0F));    // 4.3333

In the above example, we might consider to further restrict the parameter types of the functional interface since calculating the average only makes sense for numerical types. However, the functional interface only defines the signature of the Lambda expression, so it is useful to make them as generic as possible. In fact, there are a number of predefined functional interfaces available in the java.util.function package. For example, to use a Lambda expression which takes one parameter and returns a value, we can use the Function interface:

Function<Double, Double> sinsquare = x -> Math.sin(Math.pow(x, 2.0));
System.err.println(sinsquare.apply(3.4));            //  -0.844895