Java 8 - Lambda Expressions

Introduction

 
With reference to the last article, Introduction to Java 8,  Java 8 consists of various interesting features and one of them is Lambda Expressions.
Lambda Expressions means a block of code that you can pass around so it can be executed later, once or multiple times. A new operator is introduced to work with lambda expressions i.e -> operator.
 
Syntax to use lambda expressions : lambda operator -> body
 
Example : (int a, int b) - > a + b;
 

Why Lambda Expressions ?

 
Lambda expressions come into play as we had an issue while using anonymous* class; i.e its implementation is quite simple and similar as an interface that contains only one method, thus syntax seems to be unclear. Lambda expressions allow you to treat functionality as method argument or code as data and allow to express instances of single method classes more concisely.
 

Ideal Use Cases for Lambda Expressions

 
This article covers some Ideal Use Cases for Lambda Expressions which are explained below,
Create method that match one characteristic within members
A simple approach to create several methods and each method searches that particular match, this method will print the elements of the list with odd length.
  1. package LambdaExpressions;  
  2. import java.util.Arrays;  
  3. import java.util.List;  
  4. public class LambdaDemo {  
  5.     public static void main(String[] args) {  
  6.         List < String > list = Arrays.asList("Abc@d""Cde""GGhi""Km""MLno""OpDq""Qrs""Stu23");  
  7.         //using lambda expression  
  8.         list.forEach(i - > {  
  9.             if (i.length() % 2 != 0) { //check for odd length of string  
  10.                 System.out.println(i);  
  11.             }  
  12.         });  
  13.     }  

More generalized search methods
 
This method is more generic than the last one, it prints elements which satisfy the below condition, as shown this method will print the element in the list which has odd length and which start with ‘A’ or ‘a’.
 
Here startsWith (prefix) is an inbuilt method under String class in Java.
  1. package LambdaExpressions;  
  2. import java.util.Arrays;  
  3. import java.util.List;  
  4. public class LambdaDemo {  
  5.     public static void main(String[] args) {  
  6.         List < String > list = Arrays.asList("Abade""Cde""aFdfrfg""aGhi""AaIjk""ALno""apoDq""Qrs""Stu");  
  7.         //using lambda expression  
  8.         list.forEach(i - > {  
  9.             if ((i.length() % 2 != 0) && (i.startsWith("A")) || (i.startsWith("a"))) //check for odd length of string  
  10.             {  
  11.                 System.out.println(i);  
  12.             }  
  13.         });  
  14.     }  

Specify search criteria with Local Class
 
This method will simply print the elements of the arraylist, the method checks for each element of the list with the help of reference variable cons of consumerImplementclass.
 
Thus, the reference variable automatically identifies the datatype of the element and processes it further for desired output.
 
Here Consumer<T> is a functional interface with only one abstract method i.e publicvoidaccept(T t) which accepts an integer value and prints that value to console.
  1. Interface Consumer<T>  
  2. {  
  3. void accept(T t);  

Whole code will look like this,
  1. package LambdaExpressions;  
  2. import java.util.Arrays;  
  3. import java.util.List;  
  4. import java.util.function.Consumer;  
  5. //Consumer<Integer> is a functional interface with only one abstract method.  
  6. class consumerImplement implements Consumer < Integer > {  
  7.     @Override  
  8.     public void accept(Integer i) {  
  9.         System.out.println(i);  
  10.     }  
  11. }  
  12. public class localClassSearch {  
  13.     public static void main(String[] args) {  
  14.         List < Integer > list = Arrays.asList(123456789);  
  15.         Consumer < Integer > cons = new consumerImplement();  
  16.         list.forEach(cons); //will print the elements of ArrayList  
  17.     }  

Specify search criteria with Anonymous Class
 
An anonymous class enables us to make our code more concise. It allows us to declare and instantiate class simultaneously. Here, in the code below we have used an anonymous class concept where we don’t need to define the method inside the interface, we have to introduce that class and parameters at time of object creation.
  1. //Interface  
  2. interface parser {  
  3.     String parse(String str);  
  4. }  
  5. class StringParser {  
  6.     public static String convert(String str) {  
  7.         if (str.length() <= 3) {  
  8.             str = str.toUpperCase();  
  9.         } else {  
  10.             str = str.toLowerCase();  
  11.         }  
  12.         return str;  
  13.     }  
  14. }  
  15. class MyPrinter {  
  16.     public void print(String str, parser p) {  
  17.         str = p.parse(str);  
  18.         System.out.println(str);  
  19.     }  
  20. }  
  21. public class anonymousClassSearch {  
  22.     public static void main(String[] args) {  
  23.         String str = "Aman Gupta";  
  24.         MyPrinter mp = new MyPrinter();  
  25.         // Using Anonymous Class  
  26.         mp.print(str, new parser() {  
  27.             public String parse(String str) {  
  28.                 return StringParser.convert(str);  
  29.             }  
  30.         });  
  31.     }  

Specify search criteria with Lambda Expression
 
In this, Consumer<Integer> is a functional Interface, that contains only one abstract method. Since a functional interface contains only one abstract method we can omit the name of the method present inside of the interface.
 
For this, instead of using anonymous class we can use lambda Expressions as shown mp.print(str,(s) -> StringParser.convert(str));the whole code is mentioned below.
  1. //Interface  
  2. interface parser {  
  3.     String parse(String str);  
  4. }  
  5. class StringParser {  
  6.     public static String convert(String str) {  
  7.         if (str.length() <= 3) {  
  8.             str = str.toUpperCase();  
  9.         } else {  
  10.             str = str.toLowerCase();  
  11.         }  
  12.         return str;  
  13.     }  
  14. }  
  15. class MyPrinter {  
  16.     public void print(String str, parser p) {  
  17.         str = p.parse(str);  
  18.         System.out.println(str);  
  19.     }  
  20. }  
  21. public class anonymousClassSearch {  
  22.     public static void main(String[] args) {  
  23.         String str = "Aman Gupta";  
  24.         MyPrinter mp = new MyPrinter();  
  25.         // using Lambda Expressions  
  26.         mp.print(str, (s) - > StringParser.convert(str));  
  27.     }  

Using Standard Functional Interfaces with Lambda Expressions
 
As we know, Java introduced functional interfaces in its 1.8 version as an interface with only one abstract method. So there exist multiple functional interfaces like Consumer<T> , Predicate<T> etcwhich  are some standard functional interfaces.
 
Consider the following interface, the interface Predicate<T> is an example of a generic interface, we can use this interface when we have a condition which results in boolean value.
  1. interface Predicate<T> {  
  2. boolean test(T t);  

Similarly, we have another functional interface, the interface Consumer<T> an example of generic, we can use this interface when we have no result to display.
  1. Interface Consumer < T > {  
  2.     void accept(T t);  

Implementation of above mentioned interfaces is shown below,
  1. package LambdaExpression;  
  2. import java.util.Arrays;  
  3. import java.util.Collections;  
  4. import java.util.List;  
  5. import java.util.function.Consumer;  
  6. import java.util.function.Predicate;  
  7. public class LambdaWithStandardFunctionalInterface {  
  8.     public static void main(String[] args) {  
  9.         List < Person > list = Arrays.asList(new Person("ABC""DEF"10), new Person("DEF""GHI"20), new Person("GHI""JKL"30), new Person("JKL""MNO"40));  
  10.         //Prints all the elements whose firstname start with G  
  11.         printconditionally(list, p - > p.getFirstname().startsWith("G"), p - > System.out.println(p));  
  12.     }  
  13.     private static void printconditionally(List < Person > list, Predicate < Person > predicate, Consumer < Person > consumer) {  
  14.         //Predicate and Consumer are Interfaces present in Java 8  
  15.         for (Person p: list) {  
  16.             if (predicate.test(p)) consumer.accept(p); //will print the elements  
  17.         }  
  18.         System.out.println(); //new line  
  19.     }  

In the above code example, Person is a POJO(Plain Old Java Object) class and its implementation is also given below for reference,
  1. package LambdaExpression;  
  2. public class Person {  
  3.     //Member Variables  
  4.     private String firstname;  
  5.     private String lastname;  
  6.     private int age;  
  7.     public Person(String firstname, String lastname, int age) {  
  8.         super();  
  9.         this.firstname = firstname;  
  10.         this.lastname = lastname;  
  11.         this.age = age;  
  12.     }  
  13.     public String getFirstname() {  
  14.         return firstname;  
  15.     }  
  16.     public void setFirstname(String firstname) {  
  17.         this.firstname = firstname;  
  18.     }  
  19.     public String getLastname() {  
  20.         return lastname;  
  21.     }  
  22.     public void setLastname(String lastname) {  
  23.         this.lastname = lastname;  
  24.     }  
  25.     public int getAge() {  
  26.         return age;  
  27.     }  
  28.     public void setAge(int age) {  
  29.         this.age = age;  
  30.     }  
  31.     @Override  
  32.     public String toString() {  
  33.         return "Person [firstname=" + firstname + ", lastname=" + lastname + ", age=" + age + "]";  
  34.     }  

Note
*anonymous class enables us to make our code more concise. It allows us to declare and instantiate class simultaneously.
 

What di we learn?

 
After reading this article, users have a thorough knowledge of what lambda expressions are and their usage with existing Java versions. While trying to work with lambdaexpressions or any other feature of Java 8 remember to use JDK 1.8 or higher else these concepts and code will not work.
 

Summary

 
As discussed above we have learned:
  • What is Lambda Expression?
  • Why Lambda Expression?
  • Ideal UseCases for Lambda Expression.
  • Standard Functional Interfaces and more..