In this article, we’ll look at examples of Javalambda expressions and the use of lambda expressions in function interfaces, generic function interfaces, and flow apis.

Lambda expressions were first introduced in Java8. Its main goal is to improve the expressive ability of language.

Before entering lambdas, however, we first need to understand the functional interface.

What is Functional Interface?

If a Java interface contains one and only one abstract method, it is called a functional interface. Only one method specifies the intended purpose of the interface.

For example, the Runnable interface in the java.lang package; Is a function interface because it constitutes only one method, run ().

Example 1: Defining function interfaces in Java

import java.lang.FunctionalInterface;
@FunctionalInterface
public interface MyInterface{
    // the single abstract method
    double getValue(a);
}
Copy the code

In the example above, the interface MyInterface has only one abstract method, getValue (). Therefore, it is a functional interface.

Here, we use the annotation @functionInterface. Annotations force the Java compiler to indicate that the interface is a functional interface. Therefore, multiple abstract methods are not allowed. However, this is not mandatory.

In Java7, functional interfaces are treated as a single abstract method or SAM type. SAMs is typically implemented in Java7 using anonymous classes.

Example 2: Implementing SAM with anonymous classes in Java

public class FunctionInterfaceTest {
    public static void main(String[] args) {

        // anonymous class
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("I just implemented the Runnable Functional Interface."); } }).start(); }}Copy the code

Output:

 just implemented the Runnable Functional Interface.
Copy the code

Here, we can pass an anonymous class to a method. This helps you write less code in Java7. However, the syntax is still difficult and requires many extra lines of code.

Java8 further extends the capabilities of SAMs. Because we know that the function interface has only one method, we do not need to define the name of the method when passing it as a parameter. Lambda expressions allow us to do this completely.

## Introduction to Lambda expressions Lambda expressions are essentially anonymous or unnamed methods. Lambda expressions do not execute themselves. Instead, it is used to implement methods defined by the function interface.

How do I define lambda expressions in Java?

Here’s how to define lambda expressions in Java.

(parameter list) -> lambda body
Copy the code

The new operator used (->) is called the arrow operator or lambda operator. The syntax may not be clear at present. Let’s explore some examples,

Suppose we have a method like this:

double getPiValue(a) {
    return 3.1415;
}
Copy the code

We can write this method using lambda expressions, as follows:

() - >3.1415
Copy the code

Here, the method has no arguments. Therefore, the left side of the operator contains an empty argument. On the right is the lambda body, which specifies the operations of lambda expressions. In this case, it returns the value 3.1415.

The type of the Lambda body

In Java, lambda bodies come in two types.

  1. A body with a single expression
() -> System.out.println("Lambdas are great");
Copy the code

Lambda bodies of this type are called expression bodies.

  1. A body consisting of code blocks.
() - > {double pi = 3.1415;
    return pi;
};
Copy the code

Lambda bodies of this type are called blocks. A block allows a lambda body to contain multiple statements. These statements are enclosed in braces and must be followed by a semicolon.

Note: For blocks, you can use a return statement if the block returns a value. However, the expression body does not require a return statement.

Example 3: a Lambda expression

Let’s write a Java program that returns the value of Pi using a lambda expression.

As mentioned earlier, lambda expressions do not execute alone. Instead, it forms an implementation of abstract methods defined by the function interface.

Therefore, we need to define a functional interface first.

import java.lang.FunctionalInterface;

// this is functional interface
@FunctionalInterface
interface MyInterface{

    // abstract method
    double getPiValue(a);
}

public class Main {

    public static void main( String[] args ) {

    // declare a reference to MyInterface
    MyInterface ref;
    
    // lambda expression
    ref = () -> 3.1415;
    
    System.out.println("Value of Pi = "+ ref.getPiValue()); }}Copy the code

Output:

Value of Pi = 3.1415
Copy the code

In the example above,

We have created a functional interface called MyInterface. It contains an abstract method called getPiValue ()

In the main class, we declare a reference to MyInterface. Note that we can declare a reference to an interface, but not instantiate it. It is,

// it will throw an error
MyInterface ref = new myInterface();

// it is valid
MyInterface ref;
Copy the code

We then specify a lambda expression for the reference.

ref = () -> 3.1415;
Copy the code

Finally, we call the method getPiValue () using the reference interface

System.out.println("Value of Pi = " + ref.getPiValue());
Copy the code

Lambda expressions with arguments

So far, we have created lambda expressions without any arguments. However, like methods, lambda expressions can have arguments. For example, the book of job Interview and written Test

(n) -> (n%2) = =0
Copy the code

Here, the variable n in parentheses is the argument passed to the lambda expression. The lambda body takes the argument and checks whether it is even or odd.

Example 4: Using a lambda expression with arguments

@FunctionalInterface
interface MyInterface {

    // abstract method
    String reverse(String n);
}

public class Main {

    public static void main( String[] args ) {

        // declare a reference to MyInterface
        // assign a lambda expression to the reference
        MyInterface ref = (str) -> {

            String result = "";
            for (int i = str.length()- 1; i >= 0 ; i--)
            result += str.charAt(i);
            return result;
        };

        // call the method of the interface
        System.out.println("Lambda reversed = " + ref.reverse("Lambda")); }}Copy the code

Output:

Lambda reversed = adbmaL
Copy the code

So far, the function interface we have used accepts only one type of value. For example,

@FunctionalInterface
interface MyInterface {
    String reverseString(String n);
}
Copy the code

The function interface above accepts only strings and returns strings. However, we can make the function interface generic to accept any data type. If you are unsure about generics, visit Java generics.

Example 5: Generic function interfaces and Lambda expressions

// GenericInterface.java
@FunctionalInterface
interface GenericInterface<T> {

    // generic method
    T func(T t);
}

// GenericLambda.java
public class Main {

    public static void main( String[] args ) {

        // declare a reference to GenericInterface
        // the GenericInterface operates on String data
        // assign a lambda expression to it
        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"));

        // declare another reference to GenericInterface
        // the GenericInterface operates on Integer data
        // assign a lambda expression to it
        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)); }}Copy the code

Output:

Lambda reversed = adbmaL
factorial of 5 = 120
Copy the code

In the example above, we created a generic function interface called GenericInterface. It contains a generic method called func ().

So here, in the main class,

  • GenericInterface<String>reverse-Create a reference to the interface. This interface now operates on string data.
  • GenericInterface<Integer>factorial-Create a reference to the interface. In this case, the interface operates on integer data.

Lambda expressions and the StreamAPI

A new java.util.stream package has been added to JDK8, which allows Java developers to perform collections such as search, filter, map, reduce, or manipulate lists.

For example, we have a data flow (in this case, a list of strings) where each string is a combination of country name and country location. Now, we can process these data streams and retrieve places only from Nepal.

To do this, we can perform batch operations in the stream through a combination of the Stream API and Lambda expressions.

Example 6: Demonstrate using lambdas with the Stream API

import java.util.ArrayList;
import java.util.List;

public class StreamMain {

    // create an object of list using ArrayList
    static List<String> places = new ArrayList<>();

    // preparing our data
    public static List getPlaces(a){

        // add places and country to the list
        places.add("Nepal, Kathmandu");
        places.add("Nepal, Pokhara");
        places.add("India, Delhi");
        places.add("USA, New York");
        places.add("Africa, Nigeria");

        return places;
    }

    public static void main( String[] args ) {

        List<String> myPlaces = getPlaces();
        System.out.println("Places from Nepal:");
        
        // Filter places from Nepal
        myPlaces.stream()
                .filter((p) -> p.startsWith("Nepal")).map((p) -> p.toUpperCase()) .sorted() .forEach((p) -> System.out.println(p)); }}Copy the code

Output:

Places from Nepal:
NEPAL, KATHMANDU
NEPAL, POKHARA
Copy the code

In the example above, note the following statement:

myPlaces.stream()
        .filter((p) -> p.startsWith("Nepal")).map((p) -> p.toUpperCase())
        .sorted()
        .forEach((p) -> System.out.println(p));
Copy the code

Here, we use the filter (), map (), and forEach () methods of the stream API. These methods can take lambda expressions as input.

We can also define our own expressions based on the syntax we learned above. This enables us to significantly reduce the number of lines of code as we saw in the example above.

Book of Job Interview Written Test