Sunday 14 May 2017

Functional Interface and Lambda Expression

This post covers Functional interface and Lambda expression. How they are related and how we can use them to improve our code.


1. Functional Interface:

Functional interface is one of the important feature introduced in Java 8. It's one step of Java towards functional programming like C.
As we know to invoke any method we need object(for static method still we need object of class which is of Class type).
From Java 8 with the introduction of Functional Interface we can invoke a method without having object.

2. Lambda expression:

Lambda expression is a way of doing functional programming in Java. Let's see how lambda works.
Before jumping into example of lambda expression and functional interface, Let's discuss first how we used to write code so far(before Java 8), So we can compare what benefits Java 8 brings in form of Lambda and Functional Interface.
Example:
In below code we are creating an anonymous inner class at line number 3. 
How anonymous inner class works? 
Actually whenever we create an anonymous inner class like below Java internally perform following steps:
1. It creates a subclass of given type Like in our case Java will create subclass(implements) of Display interface.
2. Then Java creates object of that subclass which we later use to invoke method. Like in our case it is "display".
So if we see below code it seems like we are creating object of interface "Display", which is not possible in Java. But we are not As I mentioned above Java internally creates subclass which implements "Display" interface.
Since Java doesn't reveal the name of subclass it creates to us, that's why Java call it Anonymous inner class.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
public class LambdaExample {
 public static void main(String[] args) {
  Display display = new Display() {
   @Override
   public void show() {
    System.out.println("Hello");
    
   }
  };
  display.show();
 }
}

interface Display{
 void show();
}
Problem with above approach is we are unnecessarily creating the subclass and object of that subclass just to invoke one method "show()".

Below is the same code using Functional interface and Lambda expression.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
public class LambdaExample {
 public static void main(String[] args) {
  Display s = () -> {
    System.out.println("Hello");
    
  };
  s.show();
 }
}

interface Display{
 void show();
}
If you see above code you can notice following things:
1. Interface "Display" remain the same in both the case.
2. No "new" keyword, which suggests we are not creating any object.
In above code we have created  one method which referred using "s" and we are directly invoking the method without any object.


3. How a Functional interface is different from a normal interface:

An interface called Functional interface if it contains only one abstract method: If an interface contain more than one abstract method then it is a normal interface that can not be considered as Functional interface.
In above example we have interface "Display" which contains only one abstract method "show()" hence It is a Functional interface.

Lambda expression works only with functional interface: So in above example If we add one more abstract method in Display interface then Lambda won't work, It will give compilation error.

In oder to differentiate a functional interface from a normal interface we should use @FunctionalInterface annotation: In above example interface "Display" is an normal interface for compiler as we haven't added annotation. As far as we have only one abstract method there, lambda expression will work fine in above example.
If we add more than one abstract method, interface won't give you any error, since it is absolutely fine for a normal interface to have more than one abstract methods. But your Lambda expression will break. 
So In order to avoid accidentally addition of more than one abstract method we should annotate our functional interface as @FunctioanInterface. So compiler would give you error as soon as you try to add more than one abstract method.

1
2
3
4
@FunctionalInterface
interface Display{
 void show();
}

4. Relation between Functional interface and Lambda expression

We declare a variable in Java as below :

1
int number = 11;

Now in same way if we can declare an function in Java then It will be look like as below :
1
2
3
int show = int show(){
   System.out.println("Hello");
  }

Let's compare these two codes: 
1. Name of method is show same as name of variable number.
2. Value of method show is method body same as value of number is 11.
Now But in method declaration there are few problems, Let's correct them one by one
1.  As on Left hand side we have method name already defined as "show" so we can remove method name from right hand side. Now the code will look like as below:
1
2
3
int show = int(){
   System.out.println("Hello");
  }

2. As on Right hand side we have method return type defined as int so we can remove method return type from int to void. Now the code will look like as below:
1
2
3
int show = (){
   System.out.println("Hello");
  }

3. As on Left hand side we have method type as int. But the method type that we have on left hand side it tells about type where method belongs and that will be type of functional interface. 
So if I consider Display interface then code will look like as below:
1
2
3
Display show = (){
   System.out.println("Hello");
  }

4. Now finally we need to add Lambda operator which is "->" and the final code will look like as below:
1
2
3
Display show = () -> {
   System.out.println("Hello");
  }

Type Inference : As we can see we haven't provided return type of method which is "void" in this case. 
Type Inference is a feature for lambda expression by which Java automatically resolves the return type of method based on code, And that should match with return type of the abstract method declare in in Functional interface. 

In Display interface we have show() method whose return type is void and implementation that we have provided above that also returns nothing i.e void.
If you try to return anything from these method instead void then you will notice compiler error. For example below code will throw compiler error of return type mismatch.
1
2
3
4
Display show = () -> {
   System.out.println("Hello");
   retun 1;
  }

Same thing is applicable for type, numbers and sequence of input parameters of method as well. 

No comments:

Post a Comment