Java 8 : Lambda Expressions part 1

Lambda expressions are Java’s first step into functional programming. In Java all functions are member of classes called methods. To create a method you first need to define a class of which it is a member. A lambda expression is a block of code that represents behavior which can be created without belonging to any class. A lambda expression can be passed around as if it was an object and executed on demand. Lets see this by an example.

Lets take the Runnable interface. It has only 1 method – run(), hence a SAM (single abstract method) interface or in java 8 terms, a Functional interface. Now in order to create a thread (in earlier versions of java) and run it, you would have done one of the following:

1)Implementing an Interface: You create a class MyRunnable which implements Runnable interface, then create a Tread by passing on the MyRunnable object and then starting it.


public class MyRunnable implements Runnable {

@Override
public void run() {
System.out.println("Hello from implemening Runnable");
}

public static void main(String[] args) {
MyRunnable aMyRunnable=new MyRunnable();
Thread t=new Thread(aMyRunnable);
t.start();
}

}

2) Using an Inner class : You create a class local to your method.


public static void main(String[] args) {
Runnable aRunnable =new Runnable(){
@Override
public void run() {
System.out.println("Hello from implemening inner classs");
}};

Thread t =new Thread(aRunnable);
t.start();
}

3) Using and anonymous class : You dont give name, rather instantiating the Runnable interface and immediately passing it to the Thread constructor.


Thread t2 =new Thread(new Runnable(){
@Override
public void run() {
System.out.println("Hello from implemening anonymous classs");
}});
t2.start();

In Java 8, you can significantly reduce this code and make in lot more readable using lambda expressions. It might look like following:


Runnable r= ()-> System.out.println("Hello from Lambda");
Thread t3 =new Thread(r);
t3.start();

Breaking down the first line of the code above, which is returning the implemetation of a Runnable interface via lambda expression.

() = Method signature (run() method has no arguments)

-> = New systax called the arrow token

System.out.println(“Hello from Lambda”) = The method implementation, since its only one linem no braces are required, else curly braces must be used.

The main goal of lambda expression is to reduce the amount of code you need to write, and the number of custom classes you have to create and maintain.

Lets test using a custom interface.


@FunctionalInterface
public interface MultiplyInterface {
public int multiply(int a,int b);
}

Using the above Functional interface in our lambda expressions:


MultiplyInterface aMultiplyInterface=(a,b)->{
System.out.println("a==>"+a+"  b==>"+b);
return a*b;
};

System.out.println(aMultiplyInterface.multiply(2, 3));

As you can see, we also do not have to give types (not always, in case you have overloaded methods, you must provide types) to the arguments inside the implementation, as the types are already known in the interface, and lambda expressions is all above making the code concise.

Lambda expressions can only appear in places where they will be asigned to a variable whose type is functional Interface.

Now what if we want to use a external varialbe inside our lambda expressions.


public static void main(String[] args) {

int temp=100;
//temp=10; // local varialbe must be final or effectively final
MultiplyInterface impl1=new MultiplyInterface() {
@Override
public int multiply(int a, int b) {

System.out.println("temp==>"+temp);
return a*b;
}
};
System.out.println("Without Lambda==>"+impl1.multiply(2, 3));

MultiplyInterface impl2=(a,b)->{
System.out.println("temp==>"+temp);
return a *b;

};
System.out.println("With Lambda==>"+impl2.multiply(2, 3));
}

Output:


temp==>100
Without Lambda==>6
temp==>100
With Lambda==>6

As you can see from above, we can use an local variable, provide it is effectively final.

Lets look into the following code:


public static void main(String[] args) {

int temp=100;

MultiplyInterface impl1=new MultiplyInterface() {
@Override
public int multiply(int a, int b) {
int temp=10;
System.out.println("temp==>"+temp);
return a*b;
}
};
System.out.println("Without Lambda==>"+impl1.multiply(2, 3));

MultiplyInterface impl2=(a,b)->{
// int temp=10; //temp cannot redeclare another local variable defined in an enclosing scope.
System.out.println("temp==>"+temp);
return a *b;

};
System.out.println("With Lambda==>"+impl2.multiply(2, 3));
}

Output:


temp==>10
Without Lambda==>6
temp==>100
With Lambda==>6

As you can see from above, in annoymous/inner class we can redeclare a local varialbe, since it has its own scope, but we cannot do the same in lambda expression, because it is working with scope of method we define it in.

One of another most important addition if the foreach default method to the Iterable interface. All the Collections types implements this iterable interface. You can use lambda expressions to iterate thorugh a collection of items.


List<String> stringList=Arrays.asList("AA","aa","BB","BC","cc");
System.out.println("Old way=>");
for (String string : stringList) {
System.out.println(string);
}

System.out.println("New way=>");
stringList.forEach(string -> System.out.println(string));

Both of the above will give the same output.

Lets take another example using the Comparator functional interface. Suppose we have a List of string objects, and we sort them using the default sort method of the collections, the result will be a sorted list which case sensitive. If we are to give our own custom comparator, we would do something like this:


List<String> stringList=Arrays.asList("AA","aa","BB","BC","cc");
Collections.sort(stringList);
System.out.println("Collections.sort default case sensitive=>");
stringList.forEach(string -> System.out.println(string));
//Implementing comparator using anonmymous class
Collections.sort(stringList,new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareToIgnoreCase(o2);
}
});
System.out.println("Collections.sort comparator case insensitive=>");
stringList.forEach(string -> System.out.println(string));

Output:


Collections.sort default case sensitive=>
AA
BB
BC
aa
cc
Collections.sort comparator case insensitive=>
AA
aa
BB
BC
cc

Lets replace the custom comparator implementation (using anonymous class) with our knowledge of lambda expressions.


Comparator<String> comp= (o1,o2)-> o1.compareToIgnoreCase(o2);
Collections.sort(stringList,comp);
System.out.println("Collections.sort comparator using Lambda case insensitive=>");
stringList.forEach(string -> System.out.println(string));

As you can see, 4-5 line of code has been reduce to a single line.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: