Srikanth Technologies

Lambda Expressions

Lambda expression is one of the most important additions in Java 8. It allows us to rewrite some of the existing code in a more readable and compact way.

Java is not the first language to introduce Lambda expressions as we have languages like C#, Ruby, Scala, JavaScript etc. support lambda expressions already. In some languages like C++ lambda expressions are supported only in the recent version (C++ 11). Overall lambda expressions are here to stay. So understanding them is a must.

What is Lambda Expression?

In Java, Lambda expression is a replacement to anonymous inner class. Lambda expression allows functionality to be passed as argument to a method.

Lambda expression can be used where we have to implement an interface with single abstract method. Since Java 8 an interface can have non-abstract methods also. So lambda can replace the implementation of an interface with only one abstract method.

Let's just look at basic syntax of lambda before working with some examples.


  (parameters) ->  expression
  (parameters) ->  { // block of code }

It is important to remember that lambda expression is used where we need to use a function. So if function is supposed to return a value then even lambda expression is also expected to return a value. Parentheses for parameters are optional if you have only one parameter. If no parameter is present for the function then we need to give empty parentheses. Parentheses are needed for two or more parameters.

In the first syntax, expression is what we want to execute and whatever value it results in is the return value of the function.

In the second syntax, where we use a block of code, we need to explicitly return a value if function has to return a value. If function that lambda replaces doesn't return a value then block of code need not have a return statement.

What is Functional Interface?

Any interface that has a single abstract method (SAM) is called as functional interface.

Since Java 8 supports non-abstract methods in interface, any interface that has single abstract method with or without other kinds of methods like default and static methods is called functional interface.

In order to ensure an interface matches functional interface definition we can use @FunctionalInterface annotation with an interface.

Method Reference

When all that a lambda expression does is call a function then lambda expression can be replaced with a reference to method using the following syntax:

  Class::methodname  
  Object::methodname

When a static method is to be called then use class name, double colon(::) and static method name. For normal instance methods, we need to use an existing object.

The following example shows how to use Anonymous inner class, Lambda expression and Method reference.


 @FunctionalInterface 
 public interface Printable<T> {
    void print(T v);
    default void printLine(int size) {
        for(int i =1; i <=size; i ++)
              System.out.print('-');
    }
 }

Implementing Interface without lambda

The following is the code to implement interface Printable using anonymous inner class, lambda expression and method reference.

 // Anonymous inner class example
 Printable<String> p1 = new Printable<String>() {
   @Override
   public void print(String v) {
    System.out.println(v);
   } 
 };
 p1.print("Anonymous Inner Class");

Using Lambda Expression

Interface Printable can be implemented using lambda expression as follows:

  Printable<String> p2 = (String v) -> System.out.println(v);
  p2.print("Lambda expression");

As Java 8 understands the type of v from the context, we can rewrite the above lambda expression as follows without data type.


  Printable<String> p2 = (v) -> System.out.println(v);
  p2.print("Lambda expression");

As lambda expression is calling function println(), it is possible to replace the lambda expression with method reference as follows:


  Printable<String> p3 = System.out::println;
  p2.print("Lambda Expression With Method Reference");

Multithreading Code without Lambda

The following program shows how to create a new Thread without using lambda expression.

In order to create a thread, we need to first implement run() method that is part of Runnable interface, which is one of the functional interfaces in Java library. First let's see a program in which we use anonymous inner class to implement Runnable interface.


 public class MultiThreadingJava7 {
     public static void main(String[] args) {
         Runnable task = new Runnable() {
             public void run() {
                 for (int i=1;i <=10; i++)
                      System.out.println(i);
             }
         };
         Thread t = new Thread(task);
         t.start();
     }
 }

The same program can be rewritten in Java 8 with Lambda expression as follows:

 public class MultiThreadingJava8 {
    public static void main(String[] args) {
        Runnable task = () -> {
              for (int i=1;i <=10; i++)
                System.out.println(i);
         };
         Thread t = new Thread(task);
         t.start();
    }
 }

There are many functional interfaces in Java 8 library that can be implemented with Lambda expression. ActionListener, Comparator are examples from Java 7 and a few more like Predicate, Consumer etc. are introduced in Java 8.

Using Lambda Expression for Comparator

The following example shows how to use Lambda expression where compare() method of Comparator interface is required.

public class MyTime {
    private int hours, mins, secs;
    public MyTime(int hours, int mins, int secs) {
        this.hours = hours;
        this.mins = mins;
        this.secs = secs;
    }
    @Override
    public String toString() {
        return  String.format("%02d:%02d:%02d", hours, mins, secs);
    }     
    public int totalSeconds() {
        return  hours * 3600 + mins * 60 + secs;
    }
}


import java.util.ArrayList;

public class LambdaWithMyTime {
    public static void main(String[] args) {
         ArrayList<MyTime> times  = new ArrayList<MyTime>();
         times.add( new MyTime(10,34,30));
         times.add( new MyTime(14,15,20));
         times.add( new MyTime(7,10,50));
    
         // sort times with Lambda expression 
         times.sort((t1,t2) -> t1.totalSeconds() - t2.totalSeconds());
         times.forEach(t -> System.out.println(t));
    
         // using lambda expression 
         times.removeIf(t -> t.totalSeconds() > 3600);
    }
}
Method compare() in Comparator takes two parameters and returns int. So, lambda expression for sort also takes two parameters (t1,t2) and then executes an expression that returns an int.

Java 8 added new methods to List interface in collection framework. Two of the new methods used in the above program have the following signatures.


 removeIf(Predicate<T>)
 forEach(Consumer<T>)

Both Predicate and Consumer are functional interfaces (introduced in Java 8) and they can be replaced with lambda expression as shown in the program.

Conclusion

In many other areas of Java 8 we can use lambda expressions in place of lengthy code written in past versions. So getting comfortable with Lambda Expressions is a must for every Java programmer.