Lambda

We have already used lambda expressions in Chapter 3, Optimizing the Sort - Making Code Professional when we wrote the exception-throwing test. In that code, we set the comparator to a special value that was throwing RuntimeException at each invocation:

sort.setComparator((String a, String b) -> { 
throw new RuntimeException();
});

The argument type is Comparator; therefore, what we have to set there should be an instance of a class that implements the java.util.Comparator interface. That interface defines only one method that implementations have to define: compare. Thus, we can define it as a lambda expression. Without lambda, if we need an instance, we have to type a lot. We have to create a class, name it, declare the compare method in it, and write the body of the method, as shown in the following code segment:

public class ExceptionThrowingComparator implements Comparator { 
public int compare(T o1, T o2){
throw new RuntimeException();
}
}

At the location of use, we should instantiate the class and pass it as an argument:

sort.setComparator(new ExceptionThrowingComparator());

We may save a few characters if we define the class as an anonymous class but the overhead is still there. What we really need is the body of the one and single method that we have to define. This is where lambda comes into the picture.

We can use a lambda expression in any place where we would otherwise need an instance of a class that has to define only one method. The methods that are defined and inherited from Object do not count, and we also do not care about the methods that are defined as default methods in the interface. They are there. Lambda defines the one that is not yet defined. In other words, lambda clearly depicts, with much less overhead as an anonymous class, that the value is a functionality that we pass as a parameter.

The simple form of a lambda expression is as follows:

parameters -> body

The parameters can be enclosed between parentheses or can only stand without. The body similarly can be enclosed between the { and} characters or it can be a simple expression. This way a lambda expression can reduce the overhead to a minimum, using the parentheses only where they are really needed.

It is also an extremely useful feature of lambda expressions that we do not need to specify the types of the parameters in case it is obvious from the context where we use the expression. Thus, the preceding code segment can even be shorter, as follows:

sort.setComparator((a, b) -> { 
throw new RuntimeException();
});

The parameters, a and b, will have the type as needed. To make it even simpler, we can also omit the ( and) characters around the parameters in case there is only one.

The parentheses are not optional if there is more than one parameter. This is to avoid ambiguity in some situations. For example, the method call, f(x,y->x+y) could have been a method with two arguments: x and a lambda expression that has one parameter, y. At the same time, it could also be a method call with a lambda expression that has two parameters, x and y.

Lambda expressions are very handy when we want to pass functionality as an argument. The declaration of the type of argument at the place of the method declaration should be a functional interface type. These interfaces can optionally be annotated using @FunctionalInterface. The Java runtime has many such interfaces defined in the java.util.function package. We will discuss some of them in the next section along with their use in streams. For the rest, the standard Java documentation is available from Oracle.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.219.220.22