Java Lambda Expressions

Introduction

When implementation of anonymous class is very simple, for example, an interface contains only one method, then the syntax of anonymous classes may seem unclear. In this situation the functionality is passed as an argument to another method to perform an action, for example, when someone clicks on a button. Lambda expressions enable to treat functionality as a method argument, or code as data.

Over the years mainly two features have profoundly reshaped the Java language, fundamentally changing the way that code is written. The first was the addition of generics, added by JDK 5 and the second is the lambda expression, which is added to JDK 8. Lambda expressions significantly enhance Java because of primarily two reasons. First, they add new syntax elements that increase the expressive power of the language. Second, the addition of lambda expressions resulted in new capabilities such as the handling of for-each style operations, and the new stream API, which supports pipeline operations on data.

The more can be found at Chapter 15 of the book found at the link http://www.oracle.com/technetwork/java/newtojava/java8book-2172125.pdf

The lambda expressions mainly consist of two constructs, lambda expression and functional interface.

Lambda Expressions

A lambda expression is, essentially, an anonymous or unnamed method and it is used to implement a method defined by a functional interface. Thus, a lambda expression results in a form of anonymous class.

The lambda expression introduces new operator into the Java language and this operator is called lambda operator or arrow operator (->). It divides a lambda expression into two parts. The left side of the part specifies any parameter required by the lambda expression. The right side part is the lambda body, which specifies the actions of the lambda expression. The −> can be verbalized as “becomes” or “goes to”.

Let’s begin with the simplest type of lambda expression.

() -> 125.65 //it evaluates to constant value

The above lambda expression takes no parameter, so the parameter list is empty. It returns the constant value 125.65. Therefore, it is similar to the following method:

double myMeth() {
    return 125.65;
}

The next example:

() -> Math.random() * 50

The above lambda expression obtains a pseudo-random value from Math.random(), multiplies it by 50, and returns the result. It, too, does not require a parameter.

(x) -> (x % 2) == 0

The above lambda expression returns true if the value of parameter x is even. Most of the times you don’t need to explicitly specify the type of the parameter, x, because in many cases its type can be inferred.

Functional Interfaces

A functional interface is an interface that specifies only one abstract method. For example, the Runnable interface is a functional interface because it defines only one method: run().

With JDK 8, it is possible to specify default behavior for a method declared in an interface. This is called a default method. An interface method is abstract only if it does not specify a default implementation. Because non-default interface methods are implicitly abstract, there is no need to use the abstract modifier but if you want you can use abstract modifier.

An example of a functional interface is given below:

interface GreetingService {
    String getMessage();
}

In this case, the method getMessage() is implicitly abstract, and it is the only method defined by GreetingService. Thus, GreetingService is a functional interface, and its function is defined by getMessage().

As mentioned earlier, a lambda expression is not executed on its own. As a result, a lambda expression can be specified only in a context in which a target type is defined.

// Create a reference to a GreetingService instance.
GreetingService greetingService;

// Use a lambda in an assignment context.
greetingService = () -> "Hello, welcome to lambda expression!";

When a lambda expression occurs in a target type context, an instance of a class is automatically created that implements the functional interface, with the lambda expression defining the behavior of the abstract method declared by the functional interface.

// Call getMessage(), which is implemented by the previously assigned
// lambda expression.
System.out.println("greetingService.getMessage());

Because the lambda expression assigned to greetingService returns the value Hello, welcome to lambda expression!, that is the value obtained when getMessage() is called.

The complete example of the GreetingService lambda expression is given below.

Step 1. Create the functional interface with the below source code:

package com.roytuts.lambda;

public interface GreetingService {
    String getMessage();
}

Step 2. Create a main class which will call the getMessage():

package com.roytuts.lambda;

public class GreetingServiceDemo {
    public static void main(String[] args) {
        GreetingService greetingService = () -> "Hello, welcome to lambda expression!";
        System.out.println(greetingService.getMessage());
    }
}

Step 3. Run the above main class, you will see the below output:

Hello, welcome to lambda expression!

Another example would be as shown below:

package com.roytuts.lambda;

public class MyCalculator {
    interface IntegerMath {
        int operation(int a, int b);
    }
    public static void main(String... args) {
        IntegerMath addition = (a, b) -> a + b;
        IntegerMath subtraction = (a, b) -> a - b;
        System.out.println("40 + 2 = " + addition.operation(40, 2));
        System.out.println("20 - 10 = " + subtraction.operation(20, 10));
    }
}

Output for the above code:

40 + 2 = 42
20 - 10 = 10

In order to make sure that your functional interface should not be changed and remain always functional interface in future then you can use @FunctionalInterface annotation on the interface.

A functional interface can contain default and static methods in addition to the single unimplemented method. For example,

public interface GreetingService2{
    public void getMessage();

    public default void show(String str) {
        System.out.println(str);
    }

    public static void display(String str, PrintWriter pw) throws IOException {
        pw.write(str);
    }
}

The above interface still considered as a functional interface in Java, since it only contains a single non-implemented method.

Thanks for reading.

Related posts

Leave a Comment