Thursday, February 6, 2014

Functional interface and Lambda in Java 8

In this post, we'll see what is a functional interface in Java 8, what its use in Lambda expression and how Lambda expression is useful with detailed examples. Before that you should have an idea of static and default method in interface.

Runnable is one of the interface that we discussed in this post is used by every java programmer. What is so special in Runnable interface is that it has only one abstract method declared in their interface definition. Such interface of this type are ActionListener, Callable and Comparator.

public interface ActionListener extends EventListener {  
      public void actionPerformed(ActionEvent e);  
 }  
 public interface Callable<V> {  
      V call();  
 }  
 public interface Runnable {  
      void run();  
 } 

These interfaces are also called Single Abstract Method interfaces (SAM Interfaces).
Most of the time we use such interface by creating Anonymous inner classes. For example:

class RunnableInterfaceDemo{  
      public static void main(String javalatte[]){  
           new Thread(new Runnable(){  
                @Override  
                public void run() {  
                     System.out.println("Run method.");  
                }  
           }  
           ).start();  
      }  
 } 


import java.awt.BorderLayout;  
 import java.awt.event.ActionEvent;  
 import java.awt.event.ActionListener;  
 import javax.swing.JButton;  
 import javax.swing.JFrame;  
 class TwoInterfaceDemo{  
      public static void main(String javalatte[]){  
           JButton testButton = new JButton("Test Button");  
           testButton.addActionListener(new ActionListener(){  
                @Override  
                public void actionPerformed(ActionEvent e) {  
                     System.out.println("Click is detected");                      
                }  
           });  
              JFrame frame = new JFrame("Listener Test");  
              frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
              frame.add(testButton, BorderLayout.CENTER);  
              frame.pack();  
              frame.setVisible(true);  
      }  
 } 


Functional Interface

"An interface is considered a functional interface if it contains one and only one abstract method with no default implementation".
Conceptually, a functional interface has exactly one abstract method. Since default methods have an implementation, they are not abstract. 
If an interface declares an abstract method overriding one of the public methods of java.lang.Object, that also does not count toward the interface's abstract method count since any implementation of the interface will have an implementation from java.lang.Object or elsewhere.
Example : java.lang.Runnable, java.awt.event.ActionListener, java.util.Comparator, java.util.concurrent.Callable.
Such functional interfaces are leveraged for use with lambda expressions.

public interface Comparator<T>
is also a functional interface but question is that it declared two abstract method but why it is still function interface? one of these equals() which has signature equal to public method in Object class.
As per definition, "If an interface declares an abstract method overriding one of the public methods of java.lang.Object, that also does not count toward the interface's abstract method count since any implementation of the interface will have an implementation from java.lang.Object or elsewhere."

Lambda (λ) motivation

In mathematics, Computable functions are a fundamental concept within computer science and mathematics. The λ-calculus provides a simple semantics for computation, enabling properties of computation to be studied formally.
Computable functions are used to discuss computability without referring to any concrete model of computation.

One first simplification is that the λ-calculus treats functions "anonymously", without giving them explicit names.
For example, the function
             sqsum(x,y) = x*x + y*y
can be rewritten in anonymous form as
             (x,y) -> x*x +y*y;

Similarly, id(x) = x can be rewritten in anonymous form as x -> x

The second simplification is that the λ-calculus only uses functions of a single input. An ordinary function that requires two inputs, for instance the function, can be reworked into an equivalent function that accepts a single input, and as output returns another function, that in turn accepts a single input. For example
              sqsum(x,y) = x*x + y*y
can be reworked into
              x -> (y->x*x + y*y)

The lambda calculus consists of a language of lambda terms, which is defined by a certain formal syntax, and a set of transformation rules, which allow manipulation of the lambda terms.
As described above, all functions in the lambda calculus are anonymous functions, having no names. They only accept one input variable, with currying used to implement functions with several variables.

These are motivation behind using Lambda in Java 8 for anonymous inner classes.
Lambda expressions address the bulkiness of anonymous inner classes by converting lines of code into a single statement. This simple horizontal solution solves the "vertical problem" presented by inner classes.


Lambda Syntax in java

A lambda expression is composed of three parts.


Argument ListArrow TokenBody
(int x, int y)->x + y


The body can be either a single expression or a statement block. 
In the 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 a, int y) -> x*x + y*y : sum of square of x and y
(String str) -> { System.out.println("Welcome to Lambda Expression " + str); }


Type of Lambda expression

As functional interfaces are leveraged for use with lambda expressions. So basically is an instance of functional interface. As you see, lambda expression itself does not contain any information about which functional interface is implementing that information can been seen from the context in which we use lambda expression.
For instance,
(x,y) -> x*x + y*y
can be instance of the functional interface

interface sqsum{
  int sumsquare(int a, int b);
}
So you can write,
sqsum sm = (x,y) -> x*x + y*y

The data type that these methods expect is called the target type and can be compatible with different functional interfaces, so it use the same lambda expression. 
To determine the type of a lambda expression, the Java compiler uses the target type of the context or situation in which the lambda expression was found. It follows that you can only use lambda expressions in situations in which the Java compiler can determine a target type.
  1. Variable declarations
  2. Assignments
  3. Return statements
  4. Array initializers
  5. Method or constructor arguments
  6. Lambda expression bodies
  7. Conditional expressions, ?:
  8. Cast expressions

For example,

interface floatsqsum{
  float sumsquare(float a, int float);
}

This interface can be used with the previous lambda expression, so it can be written as
floatsqsum sm = (x,y) -> x*x + y*y


How to invoke lambda-expression in Java


  • Via functional interface
  • Functional interface – interface with one method
  • Invoke lambda-expression means to instantiate functional interface
  • Functional interface example:
    interface Runnable { void run(); }
  • Example of lambda-expression invoking
    Runnable r = () -> { System.out.println("hello"); };
    Thread t = new Thread (r);
    t.start();

Examples

Now it's time for example, these example are executed on Java(TM) SE Runtime Environment (build 1.8.0-b128) 
Example 1 : Math operation
In this example, we take one interface with one abstract method that we call functional interface now.

interface IntegerMath{  
      int operation(int a,int b);  
 }  
 public class LambdaDemo {  
      public static void main(String[] javalatteLambda) {  
           IntegerMath addition = (a,b)-> a+b;  
           IntegerMath sub = (a,b)-> a-b;  
           IntegerMath multi = (a,b) -> a*a +b*b;  
           System.out.println("Sub lambda : "+ addition.operation(4, 4));  
           System.out.println("Add lambda :"+ sub.operation(10, 4));  
           System.out.println("Multiply lambda :"+ multi.operation(10, 4));  
      }  
 } 
Output : Sub lambda : 8
Add lambda :6
Multiply lambda :116

Example 2 : Runnable interface
I hope you know that runnable interface is functional interface, so we use this in Lambda expression and we how it reduce the code from 5 lines to 1 line.
public class LambdaRunnableDemo {  
      public static void main(String[] javalatteLambda) {  
           // Anonymous   
           Runnable r1 = new Runnable(){  
                @Override  
                public void run() {  
                     System.out.println("Hello normal runnable interface");  
                }                 
           };  
           //Lambda Runnable  
           Runnable r2 = () -> System.out.println("Hello Lambda runnable interface");  
           r1.run();  
           r2.run();  
      }  
 }  
Output:
Hello normal runnable interface
Hello Lambda runnable interface


Example 3 : Comparator interface
Comparator interface abstract method look like
compare(T o1, T o2) : Compares its two arguments for order.
In this example, we'll sort a person class according to the name of the person using Anonymous class and lambda expression.

import java.util.ArrayList;  
 import java.util.Collections;  
 import java.util.Comparator;  
 import java.util.List;  
 class person{  
      private String name;  
      private int age;  
      person(String name,int age){  
           this.name=name;  
           this.age=age;  
      }  
      String getName(){  
           return name;  
      }  
      int getAge(){  
           return age;  
      }  
 }  
 public class LambdaComparatorDemo {  
      public static void main(String[] javalatteLambda) {  
           List<person> list = new ArrayList<person>();  
           list.add(new person("Pardeep",29));  
           list.add(new person("Ravi",34));  
           list.add(new person("Robert",20));  
           list.add(new person("Smith",34));  
           list.add(new person("Agtha",23));  
           //we'll sort person class with normal comparator and lambda expresion  
           Collections.sort(list, new Comparator<person>() {  
                @Override  
                public int compare(person p1, person p2) {  
                     // Asc order  
                     return p1.getName().compareTo(p2.getName());  
                }  
           });  
           System.out.println("====Sorted Asc order====");  
           for(person p : list){  
                System.out.println(p.getName());  
           }  
           // Lambda expression  
           Collections.sort(list, (person p1, person p2)-> p1.getName().compareTo(p2.getName()) );   
           System.out.println("====Lambda Sorted Asc order====");  
           for(person p : list){  
                System.out.println(p.getName());  
           }  
      }  
 }  
Output
====Sorted Asc order====
Agtha
Pardeep
Ravi
Robert
Smith
====Lambda Sorted Asc order====
Agtha
Pardeep
Ravi
Robert
Smith

Lambda expression part 2


If you know anyone who has started learning Java, why not help them out! Just share this post with them. 
Thanks for studying today!...

1 comment:

  1. Thanks Pardeep! Very helpful article on lambda. Explains well the concept and gives a good start to understand new features of Java 8.

    ReplyDelete