Java 8 : Lambda Expressions

By | April 4, 2014
Article by:
Kishan Sarsecha

Reviewed by:
Rating:
5
On April 4, 2014
Last modified:April 9, 2014

Summary:

This article contains...
Background of Lambda Expressions, Functional interface and Vertical problem.
What is a Lambda expression ?
How to use lambda.
Example of lambda expression.
Structure of lambda expression.
Type of a lambda expression.
When to use Lambda ?

This article contains…

  • Background of Lambda Expressions, Functional interface and Vertical problem.
  • What is a Lambda expression ?
  • How to use lambda.
  • Example of lambda expression.
  • Structure of lambda expression.
  • Type of a lambda expression.
  • When to use Lambda ?

Background :

1) Functional Interface :

In single line description, Interface with only abstract method are referred as Functional Interface. However, A functional interface can have more than one static or default methods, and also can Override some methods from java.lang.Object

Luckily you do not need to verify the Functional Interface, Compiler will do it for you. But you can specify @FunctionalInterface annotation to reduce it’s workload.

Below is an example of Functional interface.

interface Demo {

   // Only abstract method.
   void abc(Collection collection);

   // Functional interface can have more than one static or default methods.
   default void cdf() {
      System.out.println("This is default in Functional Interface.");
   }

   // And also can override methods of java.lang.Object
   @Override
   public String toString();
}

Some frequently used and popular Functional Interfaces are,

  • java.awt.event.ActionListener;
  • java.lang.Runnable
  • java.util.concurrent.Callable
  • java.security.PrivilegedAction
  • java.util.Comparator
  • java.io.FileFilter
  • java.beans.PropertyChangeListener

Note :
A new package in Java 8 is added that contains functional interfaces that are commonly used for lambda expression and method reference : java.util.function

2) Vertical problem :

The main problem with Anonymous classes are the syntax. For some simple operation we need to write additional syntactical code each time (However this is not true in some cases, described later in this article).
The problem of bulky syntax is refereed as “Vertical problem” by Java people.

For example : consider the ActionListener interface

button.addActionListener(new ActionListener() {
   public void actionPerformed(ActionEvent e) {
      // Do some operation.
   }
});

Above code uses additional code lines each time when you write the anonymous ActionListener class, Just to avoid writing extra class implementing ActionListener interface.

What is a Lambda Expression ?

Lambda expressions are anonymous methods, aimed at mainly addressing the “vertical problem” by replacing the machinery of anonymous inner classes with a lighter-weight mechanism in applicable cases.

How to use ?

Example :

@FunctionalInterface
interface IsFunctional {
   void testMetod(String data);
}

class LambdaChild {
   // With Anonymous class.
   IsFunctional isFunc = new IsFunctional() {
      @Override
      public void testMetod(String data) {
         System.out.println("Printing " + data + " from Anonymous class.");
      }
   };

   // With lambda expression.
   IsFunctional func = ( demoData ) -> {
      System.out.println("Printing " + demoData + " from Lambda expression.");
   };
}

Lambda expressions are implementation of only abstract method of functional interface that is being implemented or instantiated anonymously.

In above example, first one is the traditional way by creating anonymous inner class that will implement IsFunctional interface and Override testMethod().

Second one is brand new Lambda, with light syntax and no additional typing overhead.

The statements between {…} are body part of Overridden method and (…) are arguments passed to the method.

Side note :
I can see a suggestion in my NetBeans IDE 8.0 “Use Lambda Expression” where anonymous class is written in above example.

Structure of Lambda expression :

Lambda expression syntax can be divided into three parts.

1. Arrow (->) token

2. Argument List :

  • A lambda expression can contain zero or more arguments.
    // No argument.
    () -> { System.out.println("No argument"); }
    // Single argument.
    (int arg) -> { System.out.println("Single integer argument : " + arg); }
    // More than one arguments.
    ( int arg1, String arg2 ) -> { System.out.println("Two arguments : " + arg1 + " and " + arg2); }
  • You can eliminate the argument type while passing it to lambda expressions, those are inferred types. i.e. ( int a ) and ( a ) both are same.
  • More than one arguments are separated by comma (,) operator.
  • You can also eliminate “()” if there is only argument to avoid Horizontal Problem.

    ( arg ) -> {...} can be written as arg -> {...}
  • You can not use inferred and declared types together, Following is invalid.
    Example :

    ( int arg1, arg2 ) // This is invalid

3. Body of a lambda expression :

  • Body can be a single expression or a statement block.
  • If a body contains only single expression than expression will be simply evaluated and returned.
    () -> System.out.println("No argument");
  • If a body is statement of block, than it will be evaluated same as a method body, that will be called and a hidden return statement at the end block that will return control to caller after execution of block. So, branching statements ( continue and break ) are illegal and return is not necessary to write.

    () -> {
          System.out.println("Bad lambda");
          break ; // this statement is not allowed here.
       }

Type of a Lambda expression :

Example :

@FunctionalInterface
interface IsTypeOne {
   // #1 Only abstract method of IsTypeOne
   public void hasOne();
}

@FunctionalInterface
interface IsTypeTwo {
   // #1 Only abstract method of IsTypeOne
   public void hasTwo();
}

class TestType {
   // #2 Method parameter is of type IsTypeOne
   public void first( IsTypeOne one ){
      //#5 Method that is overridden by Lambda will be called.
      one.hasOne();
   }

   //#6 Method parameter is of type IsTypeTwo
   public void second( IsTypeTwo two ){
      //#9 Method that is overridden by Lambda will be called.
      two.hasTwo();
   }

   public void invoke() {
      //#3 Here labmda type is "IsTypeOne", because first() has parameter of type "IsTypeOne"
      //#4 Body {...} of lambda is body part of Overridden hasOne method.
      first(() -> { System.out.println("Invoking first."); });

      //#7 Here labmda type is "IsTypeTwo", because second() has parameter of type "IsTypeTwo"
      //#8 Body {...} of lambda is body part of Overridden hasTwo method.
      second(() -> { System.out.println("Invoking second."); });
   }
}

Explanation of above example :

  • #1 : IsTypeOne and IsTypeTwo are two different functional interfaces with only abstract method hasOne and hasTwo respectively.
  • #2 : Parameter type of first() method in TestType class is IsTypeOne
  • #3 : first() method is called from invoke() method having lambda as argument, So lambda is of type IsTypeOne.
  • #4 : Lambda expression is Overriding hasOne() of IsTypeOne interface as anonymous method.
  • #5 : Method Overridden by lambda expression will be called.
  • #6 : Parameter type of second() method in TestType class is IsTypeTwo
  • #7 : second() method is called from invoke() method having lambda as argument, So lambda is of type IsTypeTwo.
  • #8 : Lambda expression is Overriding hasTwo() of IsTypeTwo interface as anonymous method.
  • #9 : Method Overridden by lambda expression will be called.

The compiler is responsible for inferring the type of each lambda expression. It uses the type expected in the context in which the expression appears; this type is called the Target type.

In above example, target type of first() at #3 is IsTypeOne, so Compiler will use lambda type as IsTypeOne and target type of second() at #7 is IsTypeTwo, so Compiler will use lambda type as IsTypeTwo.

A lambda expression can only appear in a context whose target type is a functional interface.

A lambda expression can be assigned to a Reference which is of target type T if all of the following conditions hold:

  • T is a functional interface type
  • The lambda expression has the same number of parameters as T’s method, and those parameters’ types are the same
  • Each expression returned by the lambda body is compatible with T’s method’s return type
  • Each exception thrown by the lambda body is allowed by T’s method’s throws clause

When to use a lambda ?

Lambda is replacement of Anonymous class ? NO, Lambdas are anonymous functions which are designed to eliminate overhead (Constructor and other bulky code) of Anonymous class where it is not required.

Anonymous class :
If you want to declare constructor, some variables and going to write additional methods that will not be part of Interface, Then use Anonymous class.

Lambda Expression :
If you want to implement only method of functional interface, than use Lambda expressions or you want to pass that to other code.

Useful links :
Project Lambda : http://openjdk.java.net/projects/lambda/
Lambda FAQ : http://www.lambdafaq.org/

This was some part of lambda expression with examples, It is a quite large topic that can not be covered in detail in one article.
Hope this article will be helpful, don’t forget to post your suggestions and feedback.

You can always clone the executable code of article posted on Java By Examples from github.com
Repository URL : https://github.com/ksarsecha/java8_in.git

6 thoughts on “Java 8 : Lambda Expressions

  1. Nilendu Bhattacharya

    Hi Kishan,

    Thanks for the very details and excellent explanation. It seems that Java is adopting some features of functional programming. I started working on Scala recently and it seems Java is including functional programming which Scala has already got.

    Thanks again.

    Reply
  2. Anshudeep

    In when to use Lambdas please add the main use .. With stream API in parallel computing IMO that’s where the lambdas really shine.

    Reply
  3. Ripan

    Functional programming is very much useful for scala, spark and cacendra impl. Thanks for sharing samples with usage.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *