Monday 8 December 2014

Lambda Expressions in Java 8

Lambda expressions are a new and important feature included in Java SE 8.  A lambda expression provides a way to represent one method interface using an expression.
Lambda expression is like a method, it provides a list of formal parameters and a body (which can be an expression or a block of code) expressed in terms of those parameters.
 Lambda expressions also improve the Collection libraries making it easier to iterate through, filter, and extract data from a Collection. In addition, new concurrency features improve performance in multicore environments.

Anonymous Inner Class:
In Java, anonymous inner classes give you a way to implement classes that may occur only once in an application.
For example, in a standard Swing or SWT application a number of event handlers are required for keyboard and mouse etc.. events. Rather than writing a separate event-handling class for each event, you can write something like this.

 
 JButton testButton = new JButton("Button");
 testButton.addActionListener(new ActionListener(){
 @Override public void actionPerformed(ActionEvent ae){
     System.out.println("Action Performed in Anonymous Class");
   }
 });

Functional Interfaces:
The ActionListener example is an interface with only one method. With Java SE 8, an interface that follows this pattern is known as a "Functional Interface".

package java.awt.event;
import java.util.EventListener;
public interface ActionListener extends EventListener {    
   public void actionPerformed(ActionEvent e);
}

Functional Interfaces are leveraged for use with lambda expressions.

Lambda Expression Syntax:
Lambda expressions address the problem of anonymous inner classes by converting five lines of code into a single statement. This simple horizontal solution solves the "vertical problem" presented by inner classes.

A lambda expression is composed of three parts.


The body can be either a single expression or a statement block.
In the single expression form, the body is simply evaluated and returned.
In the block form, the body is evaluated like a method body and a return statement returns control to the caller of the anonymous method. The break and continue keywords are illegal at the top level, but are permitted within loops. If the body produces a result, every control path must return something or throw an exception.

Example:  

(int x, int y) -> x * y // 1st

() -> true              // 2nd 

(String s) -> { System.out.println(s); } // 3nd


  1. 1st: The first expression takes two integer arguments, x and y, and return x*y. 
  2. 2nd: It don't take any argument, but return false.
  3. 3rd: Prints the String into console.
Lambda Function Example with Functional Interface:

1. Runnable: You can write a Runnable using lambdas, See below code:

public class RunnableTest {
  public static void main(String[] args) {
    
    System.out.println("**** Runnable Lambda Test ****");
    
    // Anonymous Runnable
    Runnable runnableOld = new Runnable(){      
      @Override
      public void run(){
        System.out.println("Hello world OLD!");
      }
    };
    
    // Lambda Runnable
    Runnable runnableNew = () -> System.out.println("Hello world NEW!");
    
    // Run it
    runnableOld.run();
    runnableNew.run();    
  }
}

As you can see Lambda function converts five lines of code into one statement.

2. Comparator: In Java, the Comparator class is used for sorting collections.
In the following example, an ArrayList consisting of Person objects is sorted based on surName. The following are the fields included in the Person class.

public class Person {
   private String firstName;
   private String surName;
   private int age;
   
   //....................
}   

Comparing using Comparator.

public class LembdaComparator { 
  public static void main(String[] args) {   
    List<Person> personList = Person.getDummyList(); // For example 
  
    // Sort with Inner Class way
    Collections.sort(personList, new Comparator<Person>(){
      public int compare(Person p1, Person p2){
        return p1.getSurName().compareTo(p2.getSurName());
      }
    });
    
    // Use Lambda instead
    Collections.sort(personList, (Person p1, Person p2) -> p1.getSurName().compareTo(p2.getSurName()));   
  }
}

The following code will prints all list entries in the console using Lambdas:

/* sorts all elements in a collection using a lambda expression as comparator */
List names = Arrays.asList( "Test", "Test1", "Test2", "Test3" );
names.forEach( s -> System.out.println( s ) );


3. Listeners: example of  ActionListener.

public class ListenerClass {
  public static void main(String[] args) {        
    JButton testButton = new JButton("Button");
    // using anonymous class
    testButton.addActionListener(new ActionListener(){
    @Override public void actionPerformed(ActionEvent ae){
        System.out.println("Action perfromed anonymous Class");
      }
    });
    // Using Lemnbda Expression 
    testButton.addActionListener(e -> System.out.println("Action perfromed by Lambda Listner"));
  }
}

The java.util.function Package:
Functional interfaces provide target types for lambda expressions and method references.

 1. Function<T,R>this is a functional interface whose sole purpose is to return any result by working on a single input argument. It accepts an argument of type T and returns a result of type R, by applying specified logic on the input via the apply method.

// convert centigrade to fahrenheit
Function<Integer,Double> centigradeToFahrenheitInt = x -> new Double((x*9/5)+32);
 
// String to an integer
Function<String, Integer> stringToInt = x -> Integer.valueOf(x);
 
System.out.println("Centigrade to Fahrenheit: " + centigradeToFahrenheitInt.apply(centigrade))
System.out.println(" String to Int: " + stringToInt.apply("4"));


2. BiFunction<T,U,R>BiFunction represents a function that accepts two arguments and produces a result. This is the two-arity specialization of Function.

/* functions with two input parameters and one output can be implemented easily using lambdas */
BiFunction addition = ( x, y ) -> x * y;
System.out.println( "Multiplication of 5 and 7 is: " + addition.apply( 5, 7 ) );


3. Predicate<T>:  In mathematics, a predicate is commonly understood to be a Boolean-valued function P: X? {true, false}, called the predicate on X.
In java 8, Predicate a functional interface and can therefore be used as the assignment target for a lambda expression or method reference. So, where you think, you can use these true/false returning functions in day to day programming?
You can use them anywhere where you need to evaluate a condition on group/collection of similar objects such that evaluation can result either in true or false e.g.

  1. Find all children borned after a particular date
  2.  Pizzas ordered a specific time
  3.  Employees greater than certain age and so on..

Employee Class have following properties: 

public class Employee {     
   private Integer id;
   private Integer age;
   private String gender;
   private String firstName;
   private String lastName;

Some predicates on Employee Class can be:

a. All Employees who are male and age more than 18


public static Predicate<Employee> isAdultMale() {
    return p -> p.getAge() > 18 && p.getGender().equalsIgnoreCase("M");
}

b.  All Employees whose age is more than a given age


public static Predicate<Employee> isAgeMoreThan(Integer age) {
    return p -> p.getAge() > age;
}


Created another utility method filterEmployees() for using Predicate:

// Use Predicate
public static List<Employee> filterEmployees (List<Employee> empList, Predicate<Employee> predicate) {
      return empList.stream().filter( predicate ).collect(Collectors.<Employee>toList());
  }


Note: BiPredicate represents a predicate which is a boolean-valued function of two arguments.


4. Supplier<T>Suppliers represent a function that accepts no arguments and produce a result of some arbitrary type.

a. Supplier referencing a constructor method:

Supplier<Employee> empSupplier = Employee::new;
Employee emp = empSupplier.get();


b. Supplier referencing a static method:

Supplier<Employee> empSupplier = EmployeeFactory::produceEmp;
Employee emp = empSupplier.get();

class EmployeeFactory {
  public static Employee produceEmp() {
    return new Employee();
  }
}

c. Supplier referencing an instance method:

Supplier<Employee> empSupplier = this::produceEmp;
Employee emp = empSupplier.get();

private Employee produceEmp(){
  return new Employee();
}

5. Consumer<T> The Consumer accepts a single argument but does not return any result. This is mostly used to perform operations on the arguments such as persisting the employees, invoking house keeping operations, emailing newsletters etc.

a. Simple consumer: 

Consumer<Employee> empConsumer = (e) -> System.out.println("Username: " 
   + e.getFirstName());
empConsumer.accept(e);

b. Consumer applied to a stream: 

Consumer<Employee> consumer = (Employee emp) -> System.out.println("Name:"+emp.firstName +" and Age:"+emp.age);
list.forEach(consumer);

6. UnaryOperator<T>: this extends a Function acts only on same types. So, if we know that both the input and output types are the same, we could use UnaryOperator instead of Function.

UnaryOperator<String> toLowerUsingUnary = (s) -> s.toLowerCase();
String inLowerString = toLowerUsingUnary.apply("HELLO");


For more deatils See: https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html