Java Lambda Expression Tutorial

  • Post author:
  • Post category:Java

In this section, we will learn what the lambda expression is and how to use it in Java.

Prerequisite: functional interface.

What is Lambda Expression in Java?

Functional interfaces have one abstract method and to use this interface, we typically use a class to implement the target interface first and then that class becomes the base for creating new instances. Now lambda expression is a shorter and faster way of implementing a functional interface. Basically, via lambda expression, we directly define the body of the abstract method instead of invoking another class to implement the target functional interface. After creating a lambda expression, we can use it anywhere in the program that the target functional interface is needed.

Now let’s get into more details:

We know that we can’t use an interface to create an object from. This is because, in an interface, there might be an abstract method and such method is not fully defined. So what we can do is to create a class that implements the interface and use that class to create an object and then via that object call the methods of the interface.

This process happened for both functional and non-functional interfaces.

But since the Java 8 and the introduction of the lambda expression into the Java, we can use the abstract method of a functional interface without implementing the interface and creating objects.

Before getting into the details of lambda, first let’s see the traditional way of using a functional interface in a program:

Create an interface named `Functional` like this:

public interface Functional {

    void greet();
}

As you can see this interface is in fact functional because it has only one abstract method that is named `greet`.

Now create a class named `Base` that implements the `Functional` interface like this:

public class Base implements Functional {
    @Override
    public void greet() {
        System.out.println("Hello from the Base class!");
    }
}

Alright, here in this class, we’ve implemented the `Functional` interface, overridden the `greet()` method and defined a body for it.

Now let’s create an object of type `Base` and call this method:

public class Simple {
    public static void main(String[] args) {
        Functional functional = new Base();
        functional.greet();
    }
}

Output:

Hello from Base class!

The program ran without any problem.

The purpose of this program was to simply call the `greet()` method and run the instructions in its body.

But look how far we have to go just to make a simple call:

  1. Because we’re working with an interface, we need to create a class and implement the interface.
  2. Inside the class, we should define the body of the method.
  3. After that, we need to create an object.
  4. Now we can use the object to call the method!

Before the Java 8 this was the way to go. But since the Java 8 and the introduction of the lambda expression things have changed.

How to declare a lambda expression in Java? (Lambda Expression Syntax)

(parameter)->{//body…}

`(parameter)`: this is the parameter of the target abstract method that we want to define a body for it. In the last example, the abstract method of the `Functional` interface was:

void greet();

The parameter of this method is empty and so if we want to define a body for this method, we need to set a pair of empty parentheses to represent this method.

`->`: this arrow symbol is used to separate the parameter of a method from its body.

`{//body…}`: after the arrow `->` symbol, comes the body of the method. Here we define the instructions that we want the target method to have.

Note: if the target method returns a value, we need to use the keyword `return` and return a value of the same type as the return data-type of the abstract method.

So if we want to define the body of the `greet()` method via the lambda expression, that would be:

() -> {
    System.out.println("Hello from the Base class!");
};

As you can see, we first started by the empty parentheses `()` next we’ve used the arrow `->` symbol to separate the body from its parameters. And finally inside the body of the lambda, we’ve set the instructions to run when a call to the `greet()` method happened somewhere in the program.

Note: the method that is created via the lambda expression can be stored in a variable of type the interface that is the owner of the abstract method.

Example: creating lambda expression in Java

Functional fnc = () -> {
    System.out.println("Hello from the Base class!");
};

Now the body of the `greet()` method is defined and anywhere in the program we call this method via `fnc` variable, it will run the body that is created via lambda expression.

Example:

public class Simple {
    public static void main(String[] args) {
        Functional fnc = () -> {
            System.out.println("Hello from the Base class!");
        };
        fnc.greet();
    }
}

Output: Hello from Base class!

Here when we called the `fnc.greet()` method, the runtime checked the `fnc` variable and sees that the body of the `greet()` method is already defined and stored in this variable. So it will use this body anytime the call to the `gree()` method happened via `fnc` variable.

As you can see, with the help of lambda, there’s no need to create a class and implement the interface and finally use that class to create and object and call the method!!!

All those steps are now gone!

Let’s refactor this example and this time we create a method that accepts either an object of type a class that implemented a functional interface as its argument or a lambda expression that defines the abstract method of that functional interface:

public class Simple {

    public static void main(String[] args) {
        Functional f1 = () -> {
            System.out.println("Hello from the Base class!");
        };
        fnc(f1);
        fnc(() -> {
            System.out.println("Hello from the Base class!");
        });
    }

    public static void fnc(Functional functional){
        functional.greet();
    }
}

Output:

Hello from the Base class!

Hello from the Base class!

Here the `fnc` method takes one argument and that could be either an object of type a class that implemented the `Functional` interface or a lambda expression that defined the body of the `greet()` method.

So here we called this method two times:

  1. The first time we called the method just by passing the lambda expression that is stored in the `f1` variable.
  2. The second time we’ve created another lambda expression directly inside the parentheses where we put the argument of the method.

Now inside the body of the `fnc` method, anytime we call the `greet()` method, the instructions of the lambda method that is passed to the `fnc` will be executed.

Java Lambda Expression and Single Statement:

If the body of the target method is only one statement, we can remove the pair of braces `{}` and directly after the arrow `->` symbol, put that statement.

So for the last example, the body of the `greet()` method would be like this:

Functional functional = () -> System.out.println("Hello from the Base class!");

Note: this works only for one statement.

So if we refactored the example above, it would be:

public class Simple {

    public static void main(String[] args) {
        Functional functional = () -> System.out.println("Hello from the Base class!");
        fnc(functional);
        fnc(() -> System.out.println("Hello from the Base class!"));
    }

    public static void fnc(Functional functional){
        functional.greet();
    }
}

Java Lambda Expression Multiple parameters:

If in a functional interface the abstract method has a few parameters, we only need to set the parameter named of those parameters inside the parentheses of the lambda expression! The compiler will automatically set the datatype of those parameters by checking the abstract method in the target functional interface.

Note: we could also set the data type of each parameter, but that would be optional.

Example: using Java lambda expression with multiple parameters

Refactor the `Functional` interface so that the `greet()` method this time takes two parameters:

public interface Functional {

    void greet(String name, String lastName);
}

Now let’s use the lambda expression to define the body of this abstract method:

public class Simple {

    public static void main(String[] args) {
        Functional functional = (name, lastName) -> System.out.println("Hello "+ name+" "+ lastName);
        fnc(functional);
        fnc((name, lastName) -> System.out.println("Good Morning "+ name+" "+ lastName));
    }

    public static void fnc(Functional functional){
        functional.greet("John","Doe");
    }
}

Output:

Hello John Doe

Good Morning John Doe

As you can see, we didn’t use the datatype for any parameter in both lambda expressions.

Note: again remember when creating a lambda expression, the number of parameters in the parentheses of the lambda expression should match the target abstract method that we’re defining its body.

Java Lambda Expression One parameter:

If there’s only one parameter is set for an abstract method, we can simply remove the parentheses when defining a body for that abstract method via lambda expression and only use the parameter name.

Example: Java Lambda expression with one parameter

public interface Functional {

    void greet(String name);
}
public class Simple {

    public static void main(String[] args) {
        Functional functional = name -> System.out.println("Hello "+ name);
        fnc(functional);

    }

    public static void fnc(Functional functional){
        functional.greet("John");
    }
}

Output:

Hello John

Java Method reference and lambda expression

When it comes to functional interface, other than using lambda expressions to create the body of an abstract method, we can use Java reference methods as well.

This is covered in the next section.

More to Read:

Java and Method Reference

Leave a Reply