Lambda Expressions in Java

Lambda Expressions in Java

In this post, we will discuss  Lambda Expressions in Java, a new feature introduced in Java 8.

 

Introduction

Added in Java 8, lambda expressions enhance the Java performance by increasing the expressive power of the language. Before getting into Java Lambda Expressions, first, we need to understand what is a functional interface. If a Java interface that contains one and only one abstract method then it is termed as the functional interface. This only one method specifies the intended purpose of the interface. For example, the Runnable interface form package java.lang; is a functional interface because it makes up only one method i.e. run()

Here’s how you define a functional interface:

@FunctionalInterface
public interface MyInterface{
    double getValue();
}

However, the @FunctionalInterface annotation is not required, but it is wise to use it because it forces the Java compiler to show that the Interface defined is a functional interface and it must have only one abstract method. We sometimes refer the functional interface as Single Abstract Method or SAM type.

[pullquote align=”normal”]For more information, read our post on Functional interfaces in Java. [/pullquote]

 

1. What are Lambda Expressions

Lambda expression is, essentially, an anonymous or unnamed method. The lambda expression does not execute on its own. Instead, it implement a method defined by a functional interface. There will be a natural question “How to define lambda expression in Java?” The lambda expression introduces a new syntax element and operator in Java language. We refer the new operator to as the lambda operator or the arrow operator. Which is ->

Let’s write a simplest lambda expression which just returns a constant double value.

() -> 3.1415

The above lambda expression syntax is equivalent to the following method:

double getPiValue() { return 3.1415; }

The left side of the expression specifies any parameters required by the expression, whereas the right side is the lambda body, which specifies the action of the lambda expression.

 

2. Lambda Body

The lambda body is of two types.

  1. A body with a single expression () -> System.out.println(“Lambdas are great”);
  2. A body that comprises a block of code. () -> { double pi = 3.1415; return pi; }

A lambda expression can also have parameters. For example: (n) -> (n%2)==0

This lambda expression tests if the value of n is even or odd. If lambda body is a code block, you must always return a value explicitly. But, if lambda body is an expression, we do not require return statement. Let’s write a practical Java code with a lambda expression which returns the value of Pi. As mentioned earlier, the lambda expression is not executed on its own. Rather, it forms the implementation of the abstract method defined by the functional interface.

So, first define a functional interface (MyInterface.java):

import java.lang.FunctionalInterface;

// This is functional interface
@FunctionalInterface
public interface MyInterface {
    double getPiValue();
}

Now, we assign the lambda expression to the instance of the functional interface.

public class LambdaMain {
    public static void main(String[] args) {
        // create a reference to MyInterface instance.
        MyInterface myInterface;

        // use lambda in assignment context
        myInterface = () -> 3.1415;


        // call getValue() from myInterface instance, which is implemented by the previously assigned lambda expression
        System.out.println("Value of Pi = " + myInterface.getValue());
    }
}

When you run the program, the output will be:

Value of Pi = 3.1415

The lambda expression must be compatible with the abstract method. This means if you assign () -> “3.1415” to the myInterface instance, the code is illegal and won’t work because the String is not compatible with the double as defined in the functional interface.Let’s look at some other lambda expression example that takes in a parameter.

// MyInterface.java
@FunctionalInterface
public interface MyInterface {
    String reverse(String n);
}
// ParamLambdaMain.java
public class ParamLambdaMain {
    public static void main(String[] args) {
        MyInterface myInterface = (str) -> {
            String result = "";
            for (int i = str.length() - 1; i >= 0; i--)
                result += str.charAt(i);
            return result;
        };

        System.out.println("Lambda reversed = " + myInterface.reverse("Lambda"));
    }
}

When you run the program, the output will be:

Lambda reversed = adbmaL

The above functional interface only accepts String and returns a string. However, we can make the functional interface generic, so we accept any value. Let’s look at how it’s done:

// GenericInterface.java
@FunctionalInterface
interface GenericInterface<T> {
    T func(T t);
}

Now, this GenericInterface is compatible with any lambda expression that takes one parameter and returns the value of the same type.

// GenericLambda.java
public class GenericLambda {
    public static void main(String[] args) {
        GenericInterface<String> reverse = (str) -> {
            String result = "";
            for (int i = str.length() - 1; i >= 0; i--)
                result += str.charAt(i);

            return result;
        };

        System.out.println("Lambda reversed = " + reverse.func("Lambda"));

        GenericInterface<Integer> factorial = (n) -> {
            int result = 1;
            for (int i = 1; i <= n; i++)
                result = i * result;
            return result;
        };
        System.out.println("factorial of 5 = " + factorial.func(5));
    }
}

When you run the program, the output will be:

Lambda reversed = adbmaL
factorial of 5 = 120

 

3. Method Referencing using Lambda

To reference a method using a lambda, a new separator double colon added in Java 8 is used. This method reference can be used anywhere in which it is compatible with the functional interface.Static method reference syntax is:

ClassName::methodName

Reference to the instance method on specific object syntax is:

objRef::methodName

Constructor Reference syntax is:

ClassName::new

Let’s look at code example for static method reference.

// MyInterface.java
@FunctionalInterface
public interface MyInterface {
    int myFunc(int n);
}

// IntOperations.java
public class IntOperations {
    static int factorial(int n) {
        int result = 1;
        for (int i = 1; i <= n; i++) {
            result = i * result;
        }
        return result;
    }
}

// MethodRefMain.java
public class MethodRefMain {

    static int fact(MyInterface myInterface, int n) {
        return myInterface.myFunc(n);
    }

    public static void main(String[] args) {
        // static method referencing
        int result = fact(IntOperations::factorial, 5);
        System.out.println("5 Factorial = " + result);
    }
}

When you run the program, the output will be:

5 Factorial = 120

 

4. Lambdas and Stream API

The new java.util.stream package has been added to JDK8 which allows Java developers to perform operations like filter, map, reduce the collections like List. With the help of Stream API, we can do either parallel or sequential operations over the stream of data. The java.util.stream.Stream interface helpful to bulk operations. The Stream API would allow us to declare either sequential or parallel operation over the stream of data.

import java.util.Arrays;
import java.util.List;

public class StreamMain {

    public static void main(String[] args) {
        List<String> myList = Arrays.asList("Asia:India", "Asia:Nepal", "NorthAmerica:USA", "Africa:Nigeria", "Europe:UK");

        myList.stream()
                .filter(s -> s.startsWith("Asia")) // filter the data
                .map(String::toUpperCase) // map each data
                .sorted()    // sort the data
                .forEach(System.out::println); // print it
    }
}

When you run the program, the output will be:

ASIA:INDIA 
ASIA:NEPAL

[pullquote align=”normal”]Starting with Java 8 Streams? Read our article on Introduction to Java 8 Streams.[/pullquote]

 

Summary

In this article, we get a basic understanding of Lambda Expressions in Java. We discussed benefits about the Lambda Expressions and what are the different Lambda Expressions in Java.

Comments are closed.

Scroll to Top