Wednesday, February 24, 2016

Java 8 Lambda Expressions

In this blog we are going to discuss what is Lambda expression.And why it is needed.How to use it in Java.What are the benefits of using Lambda Expression.Has it some disadvantages of using it?Also we will learn about functional interface and default methods.We will move step by step from basics of Lambda Expression to its usage by simple code samples But before this we need to learn some of the backgrounds of Lambdas.

So we will learn about the followings first.
1.Functional interface
2.Anonymous inner class
3.Internal VS External iteration

1. Functional interface:

A Interface with only one abstract method are referred as Functional     Interface.But A functional interface can have more than one static or default methods .

The  below given example is a functional interface


public interface TestFunctional {

       void  doSomething(int x);

        static void staticMethod() {

              System.out.println("static method  in Functional Interface.");

           }

Some well known functional interfaces in Java are
1.java.lang.Runnable having only one abstract method  public abstract void run().
2 . java.util.concurrent.Callable<V> having only one abstract method  V call() throws Exception.
3.java.util.Comparator<T>  having only one abstract method   int compare(T o1, T o2) along with other default and static methods.

Note:We can write @FunctionalInterface to annotate the functional interfaces.
@FunctionalInterface
@FunctionalInterface

2.Anonymous inner class:

Let's take an example.Suppose we have a list of strings.And the requirement in hand is to check whether the list contains a specific string say "Lambda".
So what will we do here?There are many approaches to solve this problem.
Here we will consider the Anonymous inner class solution.

First let's declare an interface like 

package com.brainatjava;

public interface CheckWords {

    boolean test(String p);

}

package com.brainatjava;

import java.util.Arrays;
import java.util.List;

public class Test {
    static List wordList = Arrays.asList(new String[]{"a","b","Lambda","d"}); 
    public static void findString(List list, CheckWords checkWord) {
            for (String p : list) {
                if (checkWord.test(p)) {
                   System.out.println("we found Lambda anonymously.");
                }
            }
        }
    public static void main(String[] args) {
        findString(wordList,new CheckWords(){
            public boolean test(String x){
                return x.equalsIgnoreCase("Lambda");
            }
});
}
}

Here notice that, we have no class which is implementing the CheckWords interface and overrides the test method.One of the arguments of the findString method is an anonymous class, which filters the strings with some conditions ie. which is equals to Lambda.This approach reduces the amount of code required because we don't have to create a new class for each condition that we want to test.Like if we want to find the string "closure" in the given list, we can write the anonymous class in the argument of findString method to check it.However, the syntax of anonymous classes is bulky

3.Internal VS External iteration:

External iteration is  the way by which we access the elements of the collection sequentially either by using a for each loop or by using an iterator.It restricts  the opportunity to manage the elements  of the collection by not  using reordering of the data, parallelism  etc.

Example:

1:By using for each

List charcters = Arrays.asList(new String[]{"a","b","c","d"});
 for(String charcter: charcters){
            System.out.println(charcter);
        }
 2:By using iterator

 List charcters = Arrays.asList(new String[]{"a","b","c","d"}); 
 Iterator iterator = charcters.listIterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }
Sometimes it is required to consume the data of a collection in parallel or in random order which is suitable for the purpose of speed and efficiency.In this case we can avoid the sequential/insertion order  traversal of a collection .So  where order of the elements of a collection is not important  internal iteration help us to do the task in a parallel or random order.So we only have to tell what we want to do, but we don't need to specify in which order the elements will be processed.We leave this to the API to manage the order of the elements.

Introduction to Lambda Expressions:

Lambda expressions are anonymous methods that can replace the bulky code of anonymous inner class  that we described above.Simply we can say, it is a method without declaration.That is it has no name,no access modifier,no return type.And the method arguments have no type.As it will be clear from the context.We can say it is like a method we write in the same place where it will be in use.
We can say  Lambda expressions are implementation of only abstract method of a functional interface that is implemented by anonymous inner class.
It is useful where the method is used only once and the method definition is very short.It saves our effort of declaring a method with return type, name,access specifier and argument data types etc.
Lambda expressions are implementation
Lambda expressions are implementation
Lambda expressions are implementation of only abstract method of functional interface that is being implemented or instantiated anonymously. - See more at: http://java8.in/java-8-lambda-expression/#sthash.4TIhTUTQ.dpuf
Lambda expressions are implementation of only abstract method of functional interface that is being implemented or instantiated anonymously. - See more at: http://java8.in/java-8-lambda-expression/#sthash.4TIhTUTQ.dpuf

Lambda Expression structure: 

A Lambda expression has three parts
1.An arrow (->) token
2.argument list
3.body

(argument) -> (body) , is the structure of a valid Lambda expression.


argument list can have zero or more arguments.We can just think it like method arguments.

body of a Lambda expression can have zero or more statements.it can be a single statement  or a block of statements.No need to write return statements at the end of the body.The complete expression will be evaluated and returned.if the expression or statement evaluates to void ,then nothing will be returned.If the body contains a single statement no need to enclose it with curly braces.

Some Examples of Lambda Expressions:

 1.()->System.out.println("write something"); having zero argument and single statement in the body.
2.()->80 is also valid Lambda expression
3.(int x,int y)->{return x+y;} having two arguments and one statement

4.In section 2 Anonymous inner class section , We use Anonymous inner classes to instantiate objects of functional interface.Just  look at the line where we called findString() method in section 2, we used anonymous inner class to instantiate the functional  interface CheckWords.

The same can be done by Lambda expression.

public class Test {
    static List wordList = Arrays.asList(new String[]{"a","b","Lambda","d"});
    public static void findString(List list, CheckWords checkWord) {
            for (String p : list) {
                if (checkWord.test(p)) {
                   System.out.println("we found Lambda anonymously.");
                }
            }
        }
    public static void main(String[] args) {
        findString(wordList,x->
                 x.equalsIgnoreCase("Lambda")
            );
    }
}
Here we replaced the anonymous  innercalss with Lambda Expression.
What we have done here is   
CheckWords checkWord=x->x.equalsIgnoreCase("Lambda")           

That is we can write the above code as

 public  static void main(String[] args) {
 CheckWords checkWords=x->x.equalsIgnoreCase("Lambda")       
 findString(wordList,checkWord);
    }
5.As we discussed above that java.lang.Runnable is a functional interface,we can also use Lambda expression at the time of thread creation.

Let's first see the traditional  way of creating a thread.       

new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("implementing run method in an anonymous function.");
    }
}).start();
Now let's see the Lambda way of doing it.

new Thread(
    () -> System.out.println("implementing run method by Lambda expression")
).start();
The same can be written as 

Runnable runnable=  () -> System.out.println("implementing run method by Lambda   expression");   
  new Thread(runnable).start();
Lambda Expression Part2--->