How to use Lambda Expressions in java / Lambda Expressions explained

What is a Lambda expression

Suppose you have an interface which contains declaration of a method. Now, in order to define this method and call it, what steps will you take :

  1. Create a class which implements this interface.
  2. Define the interface method in the class (provide it a body).
  3. Create an object of this class and call the implemented method using this object.

With Lambda expressions, you do not need to take any of the steps to define an interface method except to define its body or what the method will do. In addition, this method will not even have any name, it will be an anonymous method. We will understand in detail about how to define a Lambda expression in this post and where is it suitable. All this discussion can be summarized as

Lambda expression is an implementation of a method defined in an interface. The implementation method will be anonymous meaning it will have NO name.

Functional Interface

In above section, it was mentioned that Lambda expression is a definition(or body) of a method declared in an interface. But, for an interface method to be eligible for conversion to a Lambda expression, the interface should be a Functional Interface. A Functional interface is an interface with ONLY ONE abstract method. Thus, any interface which has only one method declaration is a Functional Interface.

Starting from java 8, interfaces can also contain method which have a body. These methods should be preceded with default keyword.

A Functional Interface is annotated with @FunctionalInterface annotation. This is not mandatory but provides a compile time check.

Relation between Lambda Expression and Functional Interface

It should be clear till here that a Lambda expression represents a method definition and this method should belong to a Functional Interface. Now the question arises, How are Lambda expression and Functional Interface related to each other ?

Suppose you have a method M1 which takes an interface type as argument. Prior to java 8, you need to pass an object of a class which implements this interface to M1 or provide interface method definition at the place where you are calling M1. For Example, consider java.lang.Thread class. It has a constructor which expects an object of type java.lang.Runnable (an interface) as argument. We can create an object of Thread as:

1. new Thread(an object of class which implements Runnable) Or

2. // provide method definition at the required place
     new Thread(new Runnable(){
        public void run(){
            System.out.print(“New Thread”);
        }
     });

Above pieces of code when written using Lambda expression will look like

new Thread(
() -> { System.out.print(“New Thread”); }  //Lambda expression
);

Cleaner isn’t it !! Don’t worry about the syntax. We shall go into that too. For now, understand that a Lambda expression can only be used at a place where there is a requirement of Functional Interface. It is an implementation of the method defined in the Functional Interface.

Syntax of a Lambda expression

A Lambda expression is constituted of three parts:

  1. Optional Parameters : This depends on the parameters of the interface method which is represented by Lambda. Parameters can be zero, one or more.
  2. Arrow or Lambda operator : ->
  3. Body : Implementation of method. It can have zero or more statements.

Note the following points when defining a Lambda expression:

  1. When there is only one parameter, there is no need of parenthesis.
  2. Body of a Lambda expression can have zero, one or more statements.
  3. When there is only one statement in the Lambda expression, there is no need of brackets around the body part.
  4. Parameters of Lambda expression can have type associated with them or they can be defined without type. In this case, their type is determined from the context where the expression is used. Example, suppose there is a method defined in an interface which accepts 2 integer arguments and returns their product. A Lambda expression for this method can be written as (int x, int y) -> { return x * y; }. Same can also be written as (x, y) -> { return x * y; }. In the second case, their type is determined from the method declaration of the interface.

Below is a list of examples of Lambda expressions having different parameters and statements.

() -> System.out.print(“No arg Lambda”);                             // without arguments and 1 statement
() -> {
           System.out.print(“Multi Line Lambda : Line 1”);
           System.out.print(“Multi Line Lambda : Line 2”);         // without arguments and more than 1 statements
         }
(int x) ->  System.out.print(x);                                               // single argument with type and 1 statement
(x) ->  System.out.print(x);                                                    // single argument without type and 1 statement
x ->  System.out.print(x);                      // single argument without type(parenthesis omitted) and 1 statement
(int x, int y) ->  System.out.print(x);                                      // multiple arguments with type and 1 statement
(x, y) ->  System.out.print(x);                                                // multiple arguments without type and 1 statement
(x) -> return x+2;                                                                  //single argument with a return statement 

Lambda expression Usage Examples

By now, you must have understood the meaning and syntax of Lambda expressions. Below are listed various real usage examples of Lambdas along with explanation

  1. Create Runnable Object and Pass it to Thread

    new Thread (
        () -> System.out.println(“Runnable as Lambda”);
    )

    java.lang.Runnable is a Functional Interface and its run method takes no arguments and returns nothing. Hence it can be represented using a Lambda expression as () -> { // statements } where empty parenthesis represent no arguments.

  2. Binding an event to a Swing component

    JButton button  = new JButton(“Lambda Demo”);
    button.addActionListener(
    (event) -> { System.out.println(“Declared as Lambda”); }
    );

    addActionListener method takes an argument of type java.awt.ActionListener which has only 1 method actionPerformed, hence it can be represented as a Lambda expression. This method takes an event object and returns nothing. Thus, its Lambda expression has 1 argument and a print statement.

  3. When using Comparator or Comparable to sort a list

    ArrayList<String> list = new ArrayList<>();
    Collections.sort(list, (o1, o2) -> {
                return o1.compareTo(o2);
    });

    A list can be sorted using sort method of java.util.Collections class. This method takes a list to sort and an object of type java.util.Comparator. Now java.util.Comparator is a Functional interface with a method compare, hence it can be represented as a Lambda expression. This method takes 2 arguments and returns an int. Thus, its Lambda expression has 2 arguments and is returning an integer.

Remember that Lambda expression is not bound to any method or interface. This means that same Lambda can be used to represent different method definitions. Example, below Lambda takes 1 argument and returns nothing.

x ->  System.out.print(x);

Same Lambda can be used for multiple functional interfaces all of which have a method which takes 1 argument and does not return anything.

Lambda expressions as Objects

A Lambda expression can be assigned to a variable of an interface type which matches its definition. Thus the following assignment is perfectly valid.

java.util.Comparator<String> cmp = (o1, o2) -> { return o1.compareTo(o2); };

Then you can pass the above variable at any place where an object of type java.util.Comparator is expected. Also, the same Lambda expression can be assigned to any interface type whose method signature matches with the interface method.

Let’s tweak in

  1. A Lambda expression can represent only methods of an interface.
  2. A method represented by Lambda expression should be the only method in the interface.
  3. Names of parameters of a Lambda expression can be anything. They need not match the parameter names matching the actual method arguments.
  4. Every interface which has a single method is a Functional Interface. It is not necessary that it is annotated with @FunctionalInterface annotation.

For any doubts related to Lambda expression or to report any typos/errors, feel free to use the comment box below. Keep visiting !!!

Mark Your Impression

Close Menu