Java 8 Lambda Expressions


1. Overview

In this post, we will discuss the most important feature of Java 8 that is Lambda Expressions. We will learn Lambda Expressions with lots of examples by comparing Java 7 and Java 8 examples.
You can download the source code from my GitHub Repository. This blog can also help to migrate from Java 7 to Java 8.
  • Lambda Expression facilitates functional programming and simplifies the development a lot.
  • It provides a clear and concise way to represent one method interface using an expression. It is very useful in the collection library. It helps to iterate, filter and extract data from the collection.
  • The Lambda expression is used to provide the implementation of an interface which has a functional interface. It saves a lot of code. In case of the lambda expression, we don't need to define the method again for providing the implementation. Here, we just write the implementation code.
  • Java lambda expression is treated as a function, so the compiler does not create a .class file.

Functional Interface

Lambda expression provides an implementation of the Java 8 Functional Interface. An interface which has only one abstract method is called a functional interface. Java provides an annotation @FunctionalInterface, which is used to declare an interface as a functional interface.
If you have used Runnable, Callable, Comparator, FileFilter, PathMatcher, EventHandler interfaces in your projects then you can replace its implementation with Lambda Expression.
We have a separate post for Functional Interface in detail - Java 8 Functional Interface.

2. Why use Lambda Expression

  • To provide the implementation of the Java 8 Functional Interface.
  • Less coding.
  • Lambda Expressions enable you to encapsulate a single unit of behavior and pass it to other code. You can use lambda expressions if you want a certain action performed on each element of a collection, when a process is completed, or when a process encounters an error.

3. Java 8 Lambda Expressions

Java Lambda Expression Syntax
(argument-list) -> {body}  
Java lambda expression consists of three components.
  1. Argument-list: It can be empty or non-empty as well.
  2. Arrow-token: It is used to link arguments-list and body of expression.
  3. Body: It contains expressions and statements for the lambda expression.
Let's see an example without lambda expression and with the lambda expression. Here, we are implementing an interface method without using the lambda expression.

3.1 Java without Lambda Expression Example

interface Drawable{  
    public void draw();  
}  
public class LambdaExpressionExample {  
    public static void main(String[] args) {  
        int width=10;  
  
        //without lambda, Drawable implementation using anonymous class  
        Drawable withoutLambda =new Drawable(){  
            public void draw(){System.out.println("Drawing "+width);}  
        };  
        withoutLambda.draw();   
    }  
} 
Output :
Drawing 10

3.2 Java with Lambda Expression Example

Here, we are implementing an interface method using the lambda expression.
interface Drawable{  
    public void draw();  
}  
public class LambdaExpressionExample {  
    public static void main(String[] args) {  
        int width=10;         
        //with lambda 
        Drawable withLambda=()->{  
            System.out.println("Drawing "+width);  
        };  
        withLambda.draw();  
    }  
} 
Output :
Drawing 10

A lambda expression can have zero or any number of arguments. Let's discuss different ways we can write lambda expressions.

3.3 Java Lambda Expression Example: No Parameter

Please refer the comments in the code, which indicates that code with Lambda expression and without Lambda expression.
interface Sayable {
    public String say();
}
public class JLEExampleNoParameter {
    public static void main(String[] args) {
        // without lambda expression
        Sayable sayable = new Sayable() {
            @Override
            public String say() {
                return "Return something ..";
            }
        };
        sayable.say();

        // with lambda expression
        Sayable withLambda = () -> {
            return "Return something ..";
        };
        withLambda.say();
    }
}

3.4 Java Lambda Expression Example: Single Parameter

Please refer the comments in the code, which indicates that code with Lambda expression and without Lambda expression.
interface Printable {
    void print(String msg);
}

public class JLEExampleSingleParameter {

 public static void main(String[] args) {
  // without lambda expression
  Printable printable = new Printable() {
   @Override
   public void print(String msg) {
    System.out.println(msg);
   }
  };
  printable.print(" Print message to console....");
  
  // with lambda expression
  Printable withLambda = (msg) -> System.out.println(msg);
  withLambda.print(" Print message to console....");
 }
}
Output :
 Print message to console....
 Print message to console....

3.5 Java Lambda Expression Example: Multiple Parameters

Please refer the comments in the code, which indicates that code with Lambda expression and without Lambda expression.
interface Addable{  
    int add(int a,int b);  
}  
public class JLEExampleMultipleParameters {

 public static void main(String[] args) {
  
  // without lambda expression
  Addable addable = new Addable() {
   @Override
   public int add(int a, int b) {
    return a + b;
   }
  };
  addable.add(10, 20);
  
  // with lambda expression
   // Multiple parameters in lambda expression  
        Addable withLambda = (a,b)->(a+b);  
        System.out.println(withLambda.add(10,20));  
          
        // Multiple parameters with data type in lambda expression  
        Addable withLambdaD = (int a,int b) -> (a+b);  
        System.out.println(withLambdaD.add(100,200));  
 }
 
}

3.6 Java Lambda Expression Example: with or without return keyword

In Java lambda expression, if there is only one statement, you may or may not use return keyword. You must use return keyword when lambda expression contains multiple statements.
interface Arithmatic {
 int add(int a, int b);
}

/**
 * In Java lambda expression, if there is only one statement, you may or may 
 * not use return keyword. You must use return keyword when lambda expression 
 * contains multiple statements.
 * @author RAMESH
 *
 */
public class JLEExampleWithORWithOutReturnKeyword {

 public static void main(String[] args) {

  // without lambda expression
  Arithmatic addable = new Arithmatic() {
   @Override
   public int add(int a, int b) {
    return a + b;
   }
  };
  addable.add(10, 20);

  // Lambda expression without return keyword.
  Arithmatic withLambda = (a, b) -> (a + b);
  System.out.println(withLambda.add(10, 20));

  // Lambda expression with return keyword.
  Arithmatic arithmatic = (int a, int b) -> {
   return (a + b);
  };
  System.out.println(arithmatic.add(100, 200));
 }

3.7 Java Lambda Expression Example: Multiple Statements

interface IAvarage{  
    double avg(int[] array);  
}  
public class JLEExampleMultipleStatements {

 public static void main(String[] args) {
  
  // without lambda expression, IAvarage implementation using anonymous class  
  IAvarage avarage = new IAvarage() {
   @Override
   public double avg(int[] array) {
    double sum = 0;
    int arraySize = array.length;
    
    System.out.println("arraySize : " + arraySize);
    for (int i = 0; i < array.length; i++) {
     sum = sum + array[i]; 
    }
    System.out.println("sum : " + sum);
    
    return (sum/ arraySize);
   }
  };
  int[] array = {1,4,6,8,9};
  System.out.println(avarage.avg(array));
  
  // with a lambda expression
   // You can pass multiple statements in lambda expression 
  
  IAvarage withLambda = (withLambdaArray) -> {
   double sum = 0;
   int arraySize = withLambdaArray.length;
   
   System.out.println("arraySize : " + arraySize);
   for (int i = 0; i < withLambdaArray.length; i++) {
    sum = sum + withLambdaArray[i]; 
   }
   System.out.println("sum : " + sum);
   
   return (sum/ arraySize);
  };
  
  int[] withLambdaArray = {1,4,6,8,9};
  System.out.println(withLambda.avg(withLambdaArray)); 
 }
}

3.8 Java Lambda Expression Example: Creating Thread

public class JLEExampleRunnable {

    public static void main(String[] args) {
  
    //without lambda, Runnable implementation using anonymous class  
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            System.out.println(" Runnable example without lambda exp.");
        }
    };
    Thread thread = new Thread(runnable);
    thread.start();
  
     //with lambda 
    Runnable withLambda = () -> System.out.println(" Runnable example with lambda exp.");
    Thread thread1 = new Thread(runnable);
    thread1.start();
  }
}
Output :
 Runnable example without lambda exp.
 Runnable example with lambda exp.
Java lambda expression can be used in the collection framework. It provides an efficient and concise way to iterate, filter and fetch data. Following are some lambda and collection examples provided.

3.9 Java Lambda Expression Example: Comparator

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class JLEComparatorExample {

    public static void main(String[] args) {

        List<Person> listOfPerson = new ArrayList<Person>();
        listOfPerson.add(new Person("abc", 27));
        listOfPerson.add(new Person("mno", 26));
        listOfPerson.add(new Person("pqr", 28));
        listOfPerson.add(new Person("xyz", 27));

        // Without lambda expression.
        // Sort list by age
        Comparator<Person> comparator = new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                return o1.getAge() - o2.getAge();
            }
        };

        Collections.sort(listOfPerson, comparator);

        System.out.println(" sort persons by age in ascending order");
        for (Person person : listOfPerson) {
            System.out.println(" Person name : " + person.getName());
        }

        // Witht lambda expression.
        // Sort list by age

        Collections.sort(listOfPerson, (Person o1, Person o2) -> {
            return o1.getAge() - o2.getAge();
        });
        // Use forEach method added in java 8
        System.out.println(" sort persons by age in ascending order");
        listOfPerson.forEach(
           (person) -> System.out.println(" Person name : " + person.getName()));
        }
  }

class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
       super();
       this.name = name;
       this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

3.10 Java Lambda Expression Example: Event Listener

import javax.swing.JButton;  
import javax.swing.JFrame;  
import javax.swing.JTextField;  
public class LambdaEventListenerExample {  
    public static void main(String[] args) {  
        JTextField tf=new JTextField();  
        tf.setBounds(50, 50,150,20);  
        JButton b=new JButton("click");  
        b.setBounds(80,100,70,30);  
        // lambda expression implementing here.  
        b.addActionListener(e-> {tf.setText("hello swing");});  
        JFrame f=new JFrame();  
        f.add(tf);f.add(b);  
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
        f.setLayout(null);  
        f.setSize(300, 200);  
        f.setVisible(true);  
    }  
} 
One issue with anonymous classes is that if the implementation of your anonymous class is very simple, such as an interface that contains only one method, then the syntax of anonymous classes may seem unwieldy and unclear. In these cases, you're usually trying to pass functionality as an argument to another method, such as what action should be taken when someone clicks a button. Lambda expressions enable you to do this, to treat functionality as a method argument, or code as data.

Summary

  • Lambda expressions have three parts: a list of parameters, and arrow, and a body: (Object o) -> System.out.println(o);
  • You can think of lambda expressions as anonymous methods (or functions) as they don't have a name.
  • A lambda expression can have zero (represented by empty parentheses), one or more parameters.
  • The type of the parameters can be declared explicitly, or it can be inferred from the context.
  • If there is a single parameter, the type is inferred and is not mandatory to use parentheses.
  • If the lambda expression uses as a parameter name which is the same as a variable name of the enclosing context, a compile error is generated.
  • If the body has one statement, curly brackets are not required, and the value of the expression (if any) is returned.
  • If the body has more than one statement, curly brackets are required, and if the expression returns a value, it must return with a return statement.
  • If the lambda expression doesn't return a result, a return statement is optional.
  • The signature of the abstract method of a functional interface provides the signature of a lambda expression.
  • In order to use a lambda expression, you first need a functional interface.
  • However, lambda expressions don't contain the information about which functional interface are implementing.
  • The type of the expression is deduced from the context in which the lambda is used. This type is called a target type.
  • The contexts where the target type of a lambda expression can be inferred include an assignment, method or constructor arguments, and a cast expression.
  • Default methods of a functional interface cannot be accessed from within lambda expressions.
The source code of this post is available on GitHub Repository.

4. Related Java 8 Top Posts

  1. Java 8 Functional Interfaces
  2. Java 8 Method References
  3. Java 8 Stream API
  4. Java 8 Optional Class
  5. Java 8 Collectors Class
  6. Java 8 StringJoiner Class
  7. Java 8 Static and Default Methods in Interface
  8. Guide to Java 8 forEach Method
  9. Handle NullPointerException in Controller, Service and DAO Layer using Java 8 Optional Class
  10. How to Use Java 8 Stream API in Java Projects
  11. Migrating Source Code to Java 8

Comments

  1. Hi Ramesh , Thank you for the examples. could you please check 3.8 with Lamda example? I think runnable need to be passed to thread.

    ReplyDelete
    Replies
    1. Hey Udaykiran you are right for with lambda example i missed to create thread object and pass runnable object to it. Good catch thank you.

      Delete
    2. Download source code from my GitHub Repo of all Java 8 tutorials (lambda, streams, functional interface etc) on https://github.com/RameshMF/java8-developer-guide. Hope this helps you.

      Delete

Post a Comment