Lambda Expressions - Java 8 Feature

2285
Mar 20, 2016

Lambda expression is the one of major change in Java 8.0 after Generics, Annotations in Java 5.0. Lambda expressions are anonymous method similar to anonymous classes in Java.
One of great feature Java 8.0 is Lambda expression. JavaScript already has this functionality to create anonymous functions. Lambda expression allows us to create an anonymous methods in Java as well. Lets understand what is Lambda expression in Java

1. It is a method without access modifier

2. It is a method without return type declaration

3. It is a method without name


For example (int x, int y) -> { return x * y; } is a Java Lambda expression which takes two parameters and return the multiplication of these two numbers. This expression does not have access modifier (private/protected/public or default), return type and its name. same expression can be written in JavaScript like (function (x, y) { return x * y; } )

The syntax to write Lambda expression is as (arg1, arg2, ...) -> { body of expression}. Optionally the type of argument also can be specified. e.g. (int x, int y) -> { return x * y; }


Before moving further first let us understand Functional Interface. Java already has a Marker Interface which is an interface without any method in it. Similar to marker interface, Functional Interface can have only one abstract method. some of examples are Comparable which has exactly one method compareTo, Runnable which has only one method run. Java 8.0 introduced an annotation @FunctionalInterface which can be used to indicate an interface is Functional Interface.


We will create a simple test class to understand Lambda expression.

Suppose we want to sort a list of Students List<Student> by rollNumber


Student.java

package com.groupkt.lambda;

public class Student {
private Integer rollNumber;
private String name;
private Integer age;

/**
* @param rollNumber
* @param name
* @param age
*/
public Student(Integer rollNumber, String name, Integer age) {
super();
this.rollNumber = rollNumber;
this.name = name;
this.age = age;
}
/**
* @return the rollNumber
*/
public Integer getRollNumber() {
return rollNumber;
}
/**
* @param rollNumber the rollNumber to set
*/
public void setRollNumber(Integer rollNumber) {
this.rollNumber = rollNumber;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the age
*/
public Integer getAge() {
return age;
}
/**
* @param age the age to set
*/
public void setAge(Integer age) {
this.age = age;
}

@Override
public String toString() {
return new StringBuilder()
.append("{rollNumber:").append(rollNumber)
.append(",name:").append(name)
.append(",age:").append(age)
.append("}
")
.toString();
}
}

There are different ways to implement this requirement

Solution 1: By Creating a class which implements Comparable





/**
* comparator to sort by Students list by roll number
*/
private static class StudentRollNumberComparator implements Comparator<Student> {
@Override
public int compare(Student student1, Student student2) {
return student1.getRollNumber().compareTo(student2.getRollNumber());
}
}

/**
* sort the list of students by using the Implementing class of
* Comparable interface
* @param students : list of student to be sorted
*/
private static void sort(List<Student> students) {
Collections.sort(students, new StudentRollNumberComparator());
}

Here we created a class StudentRollNumberComparator which implements Comparator interface. and creates a method sort which will sort the list.

Complete class to sort the list by student's roll number by using a class which implements Comparator interface


Test.java

package com.groupkt.lambda;

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

public class Test {

public static void main(String[] args) {
List students = new ArrayList<Student>();

// create a list of students
students.add(new Student(2, "Amit", 16));
students.add(new Student(4, "Kumar", 15));
students.add(new Student(3, "Durgesh", 17));
students.add(new Student(1, "Rajendra", 14));

// call method to sort the list
sort(students);

System.out.println(students);

}

/**
* comparator to sort by Students list by roll number
*/
private static class StudentRollNumberComparator implements Comparator<Student> {
@Override
public int compare(Student student1, Student student2) {
return student1.getRollNumber().compareTo(student2.getRollNumber());
}
}

/**
* sort the list of students by using the Implementing class of
* Comparable interface
* @param students : list of student to be sorted
*/
private static void sort(List<Student> students) {
Collections.sort(students, new StudentRollNumberComparator());
}
}

This approach will solve our purpose. Here we created a class which implements Comparator.
Now let us try another approach to implement the requirement.



Solution 2: By using a anonymous class which implements Comparable


the method test can be replaced by the code as below, here we are not creating a class but directly creating an anonymous class.

/**
* sort the list of students by using anonymous class implementing
* Comparable interface
* @param students : list of student to be sorted
*/
private static void sort(List<Student> students) {
Collections.sort(students,new Comparator<Student>() {
@Override
public int compare(Student student1, Student student2) {
return student1.getRollNumber().compareTo(student2.getRollNumber());
}
});
}

This will also sort the students list, but here we have are using anonymous class.

Actually this anonymous class is implementing Comparator interface which is FunctionalInterface, and so can be replaced with the Lambda expression.



Solution 3: By using a Lambda expression


Lambda expression can be used with any functional interface and Comparator is a functional interface, so this test method can be replaced with lambda expression as below



private static void sort(List<Student> students) {
Comparator<Student> rollNumberComparator = (student1, student2) ->
student1.getRollNumber().compareTo(student2.getRollNumber());

Collections.sort(students,rollNumberComparator);
}

Here we have a lambda expression (student1, student2) -> student1.getRollNumber().compareTo(student2.getRollNumber()); which takes two student objects to compare the rollNumbers. In this expression we not specifying the type of student1 and student2 because compiler can determine the parameter types by the Comparator<Student>. In this Lambda expression
1. we have not implemented any Interface,
2. we have not created any class,
3. without method name,
4. without method return type,
5. without parameters types


All of thee solutions will give same result

[{rollNumber:1,name:Rajendra,age:14}
, {rollNumber:2,name:Amit,age:16}
, {rollNumber:3,name:Durgesh,age:17}
, {rollNumber:4,name:Kumar,age:15}
]



Related Links

Working with Date and Time API - Java 8 Feature


comments powered by Disqus

© Copyright 2017