Skip to main content

What is Lambda Expressions and its usage in Java 8?

Java 8 (version 1.8) release is notable due to a bunch of new features it brings on board. Most of the core java language changes are for fitting Lambda Expression (also called closure) in the Eco System. Java already proved itself as one of the effective object-oriented languages, with Lambda Expression in place it will be a great combination of object-oriented and functional styles of coding. In this tutorial, we will try to describe concepts that will serve as the building blocks for functional programming in Java 8.

Introduction to Lambda Expression

Lambda expression is a way to define a function or method without having any name. It enables us to encapsulate a single unit of behavior and pass it to other codes. Lambda Expression makes single method class expression more concise. Lambda Expression is made up of : Lambda Parameters -> Lambda Body For understanding how the Lambda expression can be used we are presenting one example below. Let's say we want to make a calculator functionality. Go through the example and try to understand how Lambda Expression has been used.

/*
 * (C) Mrityunjay Kumar
 * File Name: Calculator.java
 */
package com.geekmj.lambdaexpressions.example2;

public class Calculator {

    /* Functional Interface */
    interface Calculation {
 int calculate(int number1, int number2); /* Only one abstract method */

 static void doNothingStaticMethod() {
 }; /* 1st Static Method */

 static void doNothingStaticMethod2() {
 }; /* 2nd Static Method */
    }

    /*
     * a method which takes 2 int and Calculation (functional interface)
     * implementing object
     */
    public int operateNumber(int number1, int number2, Calculation calc) {
 return calc.calculate(number1, number2);
    }

    /* Functional Interface */
    interface Name {
 void print(String name); \* Only one abstract method */

    }

    public void printName(String yourName, Name name) {
 name.print(yourName);
    }

    public static void main(String\[\] args) {
 Calculator aCalculator = new Calculator();

 /* Implementation for functional Interface using Lambda Expression Below */
 /* Lambda Expression : (param1, param2, ...) -> return somedata; */
 Calculation add = (a, b) -> a + b;
 Calculation subtract = (a, b) -> a - b;

 System.out.println("40 + 2 = " + aCalculator.operateNumber(40, 2, add));
 System.out.println("40 - 2 = " + aCalculator.operateNumber(40, 2, subtract));

 /* You can directly define the Lambda Expression in argument */

 System.out.println("40 \* 2 = " + aCalculator.operateNumber(40, 2, (a, b) -> a \* b));
 System.out.println("40 / 2 = " + aCalculator.operateNumber(40, 2, (a, b) -> a / b));

 /* You may can specify the data type of Lambda Expression Parameter */
 System.out.println("80 / 2 = " + aCalculator.operateNumber(80, 2, (int a, int b) -> a / b));

 /* You may can user return statement in Lambda Expression Body */
 System.out.println("80 / 2 = " + aCalculator.operateNumber(80, 2, (int a, int b) -> {
     return a / b;
 }));

 aCalculator.printName("Mrityunjay", name -> System.out.println("You are saying your name is " + name));

 // Compilation Error : aCalculator.printName("Ram", String name
 // ->System.out.println("You are saying your name is "+name));

 aCalculator.printName("Mrityunjay", (String name) -> System.out.println("You are saying your name is " + name));

 // void statement may or may not have parentheses

 aCalculator.printName("With Parentheses void Statement", (String someText) -> {
     System.out.println("You are saying " + someText);
 });

 aCalculator.printName("Without Parentheses void Statement/expession", (String someText) -> System.out.println("You are saying " + someText));
    }

}

Functional Interface: An Interface that has only one abstract method. It may have one or more default or static methods.

A Lambda Expression can be used to implement a functional interface inline (on the fly), without creating a class or implementing the method. In this way, we can pass various Lambda expressions (different implementations) for the same functional interface in different contexts. Calculation add = (a, b) -> a + b; is implementing calculate method of Calculation Interface on the fly. Using Lambda Expression, we had successfully passed two different types of implementation for the functional interface abstract method. In System.out.println("40 * 2 = " + aCalculator.operateNumber(40, 2, (a, b)-> a * b)); statement (a, b)-> a * b) is on the fly functional interface implementation using Lambda Expression. When we introduce a second abstract method to Calculation Interface, it is no more a functional interface. When we try to use Lambda Expression for implementing non functional interface the compiler will throw an error - "The target type of this expression must be a functional interface".

Compile time error for non functional implementation of Lambda Expression

With the help of a functional interface and Lambda Expression, we can pass a function as a parameter from one method to another. This concept is known as closure. Many programming languages like JavaScript, Scala, and others had already used it.

Lambda Expression Syntax

There are 3 parts of Lambda Expression:

  1. Parameters.
  2. Arrow token ->.
  3. Body; An expression or a statement.

Parameters

A comma separated list of parameters is in parentheses. For a Single argument, we may remove parentheses. Few E.g. <b><i>(a, b)</i></b> -> a * b : Parameters in the bracket without data type. <b><i>(int a, int b)</i></b> -> a * b : Parameters in the bracket with the data type. <b><i>(int a, b)</i></b> -> a * b : It's a compilation token error. If one parameter has a data type mentioned we have to mention it for all. <i><b>a</b></i> -> System.out.println("Value " + a) : Single argument without parentheses. <i><b>(a)</b></i> -> System.out.println("Value " + a) : Single argument with parentheses. <i><b>(int a)</b></i> -> System.out.println("Value " + a) : Single argument with parentheses & data type. -> System.out.println("No Argument Lambda Expression") : You can't define Lambda Expression without any argument.

Arrow Token

-> arrow token is used to distinguish parameter from Body

Body

It can be expression <b><i>(a, b)</i></b> -> a * b  : Expression evaluated and value returned. or Statement <b><i>(a, b)</i></b> -> { return a * b; } : return statement must be enclosed in brackets and it's not expression. name -> { System.out.println("Name " + name); } : void statement with parentheses name -> System.out.println("Name " + name) : void expression without parentheses

Lambda expression use case

We had seen the way lambda expression can be used to implement functional interface.

In this section, we will explore the changes brought by lambda expression in the java platform for carrying out the various activities.

First and foremost change came in the Java platform with the introduction of Stream.

A stream is a sequence of elements. Unlike a collection, it is not a data structure that stores elements. Instead, a stream carries values from a source through a pipeline

Let say we have a list of Person (Objects) and we want to print the email id of those Person whose age is greater than 17 and less than 25.

package com.geekmj.lambdaexpressions.example3;

import java.time.LocalDate;
/*
 *
 *  File name : Person.java
 */
public class Person {
    public enum Sex {
    MALE, FEMALE
    }

    String name;
    LocalDate birthday;
    Sex gender;
    String emailAddress;
    int age;

    public Person() {

    }

    public Person(String name, LocalDate birthday, Sex gender, String emailAddress, int age) {
    super();
    this.name = name;
    this.birthday = birthday;
    this.gender = gender;
    this.emailAddress = emailAddress;
    this.age = age;
    }
    public String getName() {
    return name;
    }

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

    public LocalDate getBirthday() {
    return birthday;
    }

    public void setBirthday(LocalDate birthday) {
    this.birthday = birthday;
    }

    public Sex getGender() {
    return gender;
    }

    public void setGender(Sex gender) {
    this.gender = gender;
    }

    public String getEmailAddress() {
    return emailAddress;
    }

    public void setEmailAddress(String emailAddress) {
    this.emailAddress = emailAddress;
    }

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

    public int getAge() {
    return age;
    }
}
package com.geekmj.lambdaexpressions.example3;

/*
 *  This java code demonstrate the way we can use the Lambda Expression in Java 8
 * File Name : Example3Runner.java
 */
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;

public class Example3Runner {

    public static void main(String\[\] args) {
    \* List Of Persons */
    List Persons = new ArrayList();
    persons.add(new Person("Ram", LocalDate.of(1982, 01, 11), Person.Sex.MALE, "ram@email.com", 11));
    persons.add(new Person("Shyam", LocalDate.of(1984, 01, 11), Person.Sex.MALE, "shyam@email.com", 14));
    persons.add(new Person("Sita", LocalDate.of(1990, 01, 11), Person.Sex.FEMALE, "sita@email.com", 17));
    persons.add(new Person("Gita", LocalDate.of(1992, 01, 11), Person.Sex.FEMALE, "gita@email.com", 8));
    persons.add(new Person("Radha", LocalDate.of(1987, 01, 11), Person.Sex.FEMALE, "radha@email.com", 18));

    /*
     * Printing List of Persons Whose Age is between 8 and 11
     */

    /* Using Aggregate Operations that accept Lambda Expression */
    System.out.println("\*\*\* Using Aggregate Operations which accept Lambada Expression to print the stuff \*\*\*");

    persons.stream().filter(p -> p.getGender() == Person.Sex.MALE && p.getAge() >= 8 && p.getAge() <= 18).map(p -> p.getEmailAddress())
        .forEach(email -> System.out.println(email));

    }
}

References:

  1. Lambda Expressions from Java Tutorial

Comments

Popular posts from this blog

Working with request header in Jersey (JAX-RS) guide

In the  previous post , we talked about, how to get parameters and their values from the request query string. In this guide learn how to get request header values in Jersey (JAX-RS) based application. We had tested or used the following tools and technologies in this project: Jersey (v 2.21) Gradle Build System (v 2.9) Spring Boot (v 1.3) Java (v 1.8) Eclipse IDE This is a part of  Jersey (JAX-RS) Restful Web Services Development Guides series. Please read Jersey + Spring Boot getting started guide . Gradle Build File We are using Gradle for our build and dependency management (Using Maven rather than Gradle is a very trivial task). File: build.gradle buildscript { ext { springBootVersion = '1.3.0.RELEASE' } repositories { mavenCentral() } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") } } apply plugin: 'java' apply plugin: 'eclipse' a

Ajax Cross Domain Resource Access Using jQuery

Some time back in our project we faced a problem while making an Ajax call using jQuery. Chrome Browser console had given some weird error message like below when we try to access one of our web pages: When we try to access the same web page in the Firefox browser, it doesn't give any error in the console but some parsing error occurred. In our case, we were accessing XML as an Ajax request resource. I was curious to check if the non-XML cross-domain resource was successfully loading or not. But finally, I realized that it is not going through. jersey-spring-boot-quick-starter-guide In our Ajax call, requesting domain was not the same as the requested URL domain. $.ajax({ url: "https://10.11.2.171:81/xxxxxx/xxxxxxx.xml" , type : "get" , success: function (response) { alert( "Load was performed." ); }, error : function (xhr, status) {

FastAPI first shot

Setup on my Mac (Macbook Pro 15 inch Retina, Mid 2014) Prerequisite Python 3.6+ (I used 3.7.x. I recently reinstalled OS after cleaning up disk, where stock Python 2.7 was available. I installed Pyenv and then used it to install 3.7.x). I already had a git repo initialized at Github for this project. I checked that out. I use this approach to keep all the source code safe or at a specific place 😀. I set the Python version in .python-version file. I also initialize the virtual environment using pyenv in venv folder. I started the virtual environment. FastAPI specific dependencies setup Now I started with basic pip commands to install dependency for the project. I saved dependencies in requirements.txt  the file. Minimal viable code to spin an API Server FastAPI is as cool as NodeJS or Go Lang (?) to demonstrate the ability to spin an API endpoint up and running in no time. I had the same feeling for the Flask too, which was also super cool. app/main.py: from typing i