refermycode.com

Develop your world..

Lambda Expression with Example

Hi Techies,

In previous blog, we have learned basic introduction of Lambda Expression. Now, we are going to learn few examples and some new APIs using Lambda Expression in detail. so before proceeding further, lets brush up some basic concepts of Lambda Expressions in something different way.

What is Lambda?

  • A Lambda is a function.
  • A function is computation that takes parameters and return value.
  • Until Java 8 function could be implemented by using methods.
  • A Lambda enables function to be passed around or stored like data.

Let us consider following example of sorting the list of Person objects with the name of person.

This is basic syntax to sort a list of object.

So in above example collections.sort() method requires parameter of type comparator, so we need to wrap compare method to one class which should need to implements comparator interface. But still we cannot call comparator class because sort method needs instance of comparator interface. so we are creating instance of comparePersonByName() class and passed to the sort method. So basically we are passing instance of comparator to the sort method.

This is sometimes becomes a problem because, The class that defines comparator sometime is far away from where it used. If our application have multiple files then it is difficult to figure out where actually comparator is located in our file system.

In order to deal with this problem, We can inline the compare() method inside an anonymous inner class. This avoids problem of declaring class into the somewhere else.

But there is lot of complexity here, both in the syntax and in fact we are creating a class and creating an instance of it, and just passing that instance to a function to sort method.

So let’s remove some syntax from this Collection.sort() method to simplify the structure of the code.

So now our syntax contains a method body which takes a 2 parameters Person p1 and Person p2 and perform some operation on it with compareTo() method and returning value to the Collection.sort() method.

So we can rewrite this into our first Lambda Expression, it just a function like,

So parameter are passed on the left side of an expression and list of parameters are enclosed with the parenthesis. The body of lambda expression are defined on the right side of special symbol -> (Arrow syntax) which is basically used to declare a Lambda Expression.

We can reduce the code Syntax as further,

Since we are sorting a list of Persons, the comparator function must be comparison of 2 Persons. The compiler knows this and hence it uses Type Inference to determine the types of parameters.We left off the type decoration making the Lambda Expression even more concise.

Note that, Java is still statically tie, means the type of p1 and p2 are still Person. They are determined at compile time. If compiler does not have information to infer what the type of p1 and p2 then it will generate the compile time error.

The sort method still calling compare() method, Even if we have not declared any compare method in the syntax of above mentioned Lambda expressions then How would you know that it is compare method?

Here is the answer,

Comparator is a special kind of interface called as functional interface. If you are declare a class which implements an interface then you need to provide implementation of each method declared in it. A Functional interface is an interface where you only have to implement a single method. In case of comparator it is the method called compare(). But since there is only a single method that you need to implement when you provide a Lambda Expression for it you don’t have need to provide the name, the Lambda Expression implicitly implements that single method inside the functional interface.

The all syntax which is used in the Lambda Expression we are already studies in the previous blog. If you want to know about the all syntax then please go through the previous blog.

Now we are going to learn why Functional Interfaces are important?

Anywhere functional interface is taken as argument you can write a Lambda Expression for it. Lets check out some other functional interfaces that already existed in Java 7, even though they wouldn’t called as functional interfaces previously.

A common example Is the Runnable interface. It defines a single method called run(). To create a new thread, you need to pass instance of Runnable interface to the Thread constructor. The tread will invoke the run method of Runnable interface. So below example will show how to create a thread using anonymous inner class.

so we can use the following Lambda Expression to perform the same operation which is mentioned in above example.

So in many cases the expression declared in anonymous inner class is replaced with Lambda expression.

New APIs using Functional Interfaces:

Oracle have added several new APIs in Java 8 that takes an functional interface and hence we can use Lambdas in it. For example let us consider the task to printing out each person in a list of Person.

Example 1:

We can use new forEach() loop to print out the list of Person with the help of Lambdas.

It might not seems very significant it look like we have just rearrange the syntax but this is an example of Internal iteration vs External iteration.

Lets us modify this list into the synchronized version of list, so that following example will make difference between Internal iteration and external iteration more clear.

so now this version list is a synchronised list which can be operated by multiple threads simultaneously.

The for loop which in body External iteration is implemented by using iterator. The for loop repetitively call the hasNext() and next() method of iterator (i.e. Two methods are concurrently working on the list). Since the list is synchronised list each method call on the iterator is synchronized, however another thread can modify the list between these calls if this occurs next method call on iterator results in concurrentModificationException. This example shows that the loop is been control from outside of list hence it is External iteration.

The forEach method on list illustrates Internal iteration. This is single method called on a list so list is synchronized for the entire duration of call and in such condition concurrent modification is not possible. Iteration of whole list Happens inside the single call hence it is Internal iteration.

Example 2:

Here is the another example in which we have to remove the all persons from list which having name equals to “ABC”. So we can find all such a type of person by using conventional for loop, but we can’t do the actual removal of that object. The reason is that we can only remove element by using remove() method of iterator but in for loop we do not have access to iterator that the for loop is using.

Instead of that, we need to write the for loop into long form, i.e. we have to explicitly get the iterator in advance using hasNext() and next() methods. Then we can call remove() method in appropriate place when we found person which match the criteria inside the loop.

In java 8, we can handle this situation by using new method removeIf() which removes each element from list where Lambda Expression returns the value as true.

Example 3:

Here is another example with new method which is used with Lambdas. Suppose we have to replace each element of list with uppercase equivalent. We can use same for loop which is use in the previous example with listIterator. Within the iterator we can use the set method listIterator to replace the new values with its uppercase in the same location.

So we can perform same operation with the help of Lambda Expression by using replaceAll() method.

Default Methods :

In Java 8, oracle has added new feature called as Default Methods, Default Methods has an implementation inside the interface, so for any class that has not provided implementation of this methods, the default implementation is used instead of that.

Default Methods are just like virtual methods, they can be overridden by subclasses. So following are the default methods which are added into the respective interface.

The list.sort() is replacement of Collection.sort() method,
Here is example of list.sort() method,

Above syntax can be replaced with,

Higher Order Functions :

Lets consider the following example which is used to sort the list with the help of comparator. In many cases same structure is used to sort the list with following manner,

Wouldn’t be nice if we can replicate that structure more easily?
So oracle introduce new method called Comparator.comparing(). this is higher order function, which is function that consumes or returns other functions.

In this case, comparing function takes function and gets right data from person object, this getter is called on each of the two Person objects and calls compareTo() on that values. The comparing function doesn’t do the comparison itself instead it construct the comparator function and returns it and this return is passed to list.sort() method.

Method References :

We have seen few lambda expression which are in the form of given an object, called method on that object and return the result. This form of lambda are so common, oracle has created a shorthand for it called as Method References. Using the new :: operator, we can mention a method by classname and methodname and it is equivalent to writing a Lambda Expression that takes an object if that type and calls the method on it.
Here we are rewritten the previous examples by using method references,

Two Level Sorting :

Let’s move to more complicated example of 2 level sorting. Suppose we want to sort the list with the age of Person and within the same group of age we have to sort the list by the name. So below is the code to sort the list using anonymous class,

In this example first compareTo() method is returning the result of ages while second compareTo() method is returning the result of comparing the names.

So it’s looking very complicated but if we break it down then we observe that it is combining the result of two comparators. Means if result is unequal then we are done and if result is equal then we call the second comparator and return its result.

We can use higher order functions to take two comparators and combine them into one.

So here the higher order function because it takes one function as parameter and returns value if that function to another function,

So firstly, we are sorting the list with the age with the help of first comparator which is invoked by comparing() method, if result of this comparator is equal then the result of this function is passing to another comparator which is sorting the list with the name with the help of new method thenComparing().

We can make this code more concise with static import,

So code readability is also increased by using the Lambda Expressions.

Old vs New :

Here is same code with the Lambda Expression,

here is the old and new code, side by side, Not only does old code have lot of inner class where embed it also embed some logic that isn’t very obvious. If you reading this code for first time then it can be hard to understand. By contrast the lambda based code makes it easy to create a very complicated structure by composition of small parts. Its pretty easy to create comparator using comparing() function. Its also pretty easy to combine comparator using the thenComparing() method. The resulting code is clear,concise and easy to modify.

Summary :

  • Lambdas are functions.
    A lambda can often replace an anonymous inner class.
  •  Java SE 8 defines new APIs using functional interfaces.
    Java 8 defines several new functional interfaces and new APIs that use them enabling them to be used with Lambdas.
  • Default Methods
    Default methods enable interfaces to view add compatibility.
  • Method References
    Method references are used for short hand Lambdas.
  • Higher Order Functions
    Higher Order Functions enables creation of more complex functions by composition of simple functions.

Lambdas make code read more like the problem statement. The resulting code is clear, concise and easy to maintain and modify.

Hope this blog will help you to understand some new APIs using Lambda Expression with Example in Java 8.
Please don’t forget to comment your feedback for this post. 🙂

References : Video of Stuart Marks – Oracle Corporation.
Image Courtesy : http://blog.takipi.com/compiling-lambda-expressions-scala-vs-java-8/