Introduction :
Lambda Expressions enable us to treat functionality as a method argument or code as data . Well, What is functionality as a method argument? Did we already use this before? Yes, the answer is yes, we already used this concept before with anonymous classes. In anonymous classes case, we are usually trying to pass functionality as an
argument to another method. Lambda expressions are also to do this. Although anonymous classe is often more concise than a named class, for classes
with only one method, even an anonymous class seems a bit
excessive and cumbersome.
Usage :
First let us discuss the usage of the Lambda Expressions then will go through the syntax of Lambda Expressions.Suppose that you are creating an application for car sellers. You
are asked to create a feature that search cars by certain criteria.
Car class can be represented as follows.
Car class can be represented as follows.
public class Car{
public enum Color {
BLACK, WHITE, RED
}
public String modelName;
public Color color;
public int engineCC;
public void printModelName() {
// ...
}
}
Now you need to implement a feature that search for cars that match one characteristic such as engine cc.One simplistic approach is create a method that searches for cars that match one characteristic, such as engine cc. The following method prints Model name that are greater than the specified engine CC.
public void searchCarsGreaterThanCC(List<Car> cars, int cc) {
for (Car c : cars) {
if (c.engineCC > cc) {
c.printModelName();
} } }This approach can potentially make your application brittle,Suppose that you upgrade your application and change the structure of the Car class such that it contains different member variables; perhaps the class records and engineCC with a different data type. You would have to rewrite the logic to accommodate this change. In addition, this is very restrictive, for example if you wanted to get the models with lesser that certain engineCC. What will you do?
So will go for more generic search method that get cars with in the specified range of engine CC.
public void searchCarsWithinCCRange(
List<Car> cars, int lowCC, int highCC) {
for (Car c : cars) {
if (lowCC <= c.engineCC && c.engineCC < highCC) {
c.printModelName();
}
}
}
This approach also restrictive, What if you want to get a specified color of cars or combinations of color and engineCC? You can separate the code that specifies the criteria for which you want to search in a different class, for this create an interface SerachCar with one filter method and implement the method for any criteria.The following method prints model names that match search criteria that you specify:public void searchCars(
List<Car> cars, SerachCar filter) {
for (Car c : cars) {
if (filter.filter(c)) {
c.printModelName();
}
}
}
This method checks each Car,whether it satisfies the search criteria specified in the SerachCar parameter filter by invoking the method filter.filter. If the method filter returns a true value, then the method prints the model name of the car.To specify the search criteria, you need to implement the SerachCar interface:
interface SerachCar {
boolean filter(Car c);
interface SerachCar {
boolean filter(Car c);
}The following class implements the SerachCar interface by specifying an implementation for the method
filter
. This method filters cars that are Red and above 500engine CC.class SerachCarWithRedAndAbove500CC implements SerachCar {
public boolean filter(Car c) {
return c.color == Car.Color.RED &&
c.engineCC >= 500 ;
}
}
then we can use above class to search the cars as follows
searchCars(cars, new SerachCarWithRedAndAbove500CC ());
Although this approach is less brittle—you don't have to rewrite methods if you change the structure of the Car,
but you still have additional thing you need to do is a local class for each
search is to create. Instead writing classes for each criteria you can use an anonymous class.The second argumnet of the method searchCars is an anonymous class that filters members that are eligible for Red and above 500CC car.
searchCars (cars,
new SerachCar() {
public boolean filter(Car c) {
return c.color == Car.Color.RED
&& c.engineCC >= 500 ;
}
}
);
By this approach, you no need to create a new class for each search that you want to perform. However, If you the observe the syntax of anonymous classes is bulky as you need to implement the method with class as as argument.In this case, you can use a lambda expression instead of an anonymous class.So we came to our actual topic now.
The SerachCar interface is a functional interface. A functional interface is any interface that contains only one abstract method. (A functional interface may contain one or more default methods or static methods.) Because a functional interface contains only one abstract method, you can omit the name of that method when you implement it. To do this, instead of using an anonymous class expression, you use a lambda expression.
The following is the actual syntax of lambda expressions, method invocation is shown here with lambda expressions instead anonymous class
serachCars(cars,
(Car c) -> c.color == Car.Color.RED &&
c.engineCC >= 500
);
If you observe the method invocation with anonymous class and lambda expressions, with anonymous class invocation you are specifying the interface name and also method name with implementation. But with lambda expression they are not required, then how does compiler understand?,Well. The answer is very simple, compiler knows the interface by method signature and that interface has only one method as it is functional interface so only one method should be implement. the code what you are passing as a argument is nothing but the implementation of the method.
Syntax:
Did you get the meaning of the lambda expressions which is used in SerachCar method invocation?The meaning is very simple to understand, the SearchCar method's second argument is functional interface(only one default method) and the right hand side of the arrow token in lambda expression is the implementation code of that default method and the left hand side of the arrow token is the argument of the default method. You can compare the same with anonymous class
public boolean filter(Car c) {
}is
(Car c) ->
and
public boolean filter(Car c) {
return c.color == Car.Color.RED &&
c.engineCC >= 500
}
is
(Car c) -> c.color == Car.Color.RED && c.engineCC >= 500
More on Lambda Expressions Syntax:
- If the method as more than one argument then a comma-separated list of formal parameters enclosed in parentheses. (a, b) -> a + b;
- You can omit the data type of the parameters in a lambda expression. (c) -> c.color == Car.Color.RED && c.engineCC >= 500
Note: How does compiler resolve the data type? Again the answer is same by the method signature of default method in functional interface
- You can also omit the parentheses if there is only one parameter.
c -> c.color == Car.Color.RED && c.engineCC >= 500
- The right side of arrow token, we can call that as body,which consists of a single expression or a statement block.
- If you specify a single expression, then the Java runtime evaluates the expression and then returns its value.Other wise, you can use a return statement:
c -> {
return c.color == Car.Color.RED && c.engineCC >= 500;
return c.color == Car.Color.RED && c.engineCC >= 500;
}
- If a return statement is not an expression; in a lambda expression, you must enclose statements in braces ({}).
- However, you do not have to enclose a void method invocation in braces.
- Lambda expression looks a lot like a method declaration, you can consider lambda expressions as anonymous method (methods without a name).
public class Calculator { interface IntegerMath { int operation(int a, int b); } public int operateBinary(int a, int b, IntegerMath op) { return op.operation(a, b); } public static void main(String... args) { Calculator myApp = new Calculator(); IntegerMath addition = (a, b) -> a + b; IntegerMath subtraction = (a, b) -> a - b; System.out.println("40 + 2 = " + myApp.operateBinary(40, 2, addition)); System.out.println("20 - 10 = " + myApp.operateBinary(20, 10, subtraction)); } }The method
operateBinary
performs a mathematical operation on two integer operands. The operation itself is specified by an instance of IntegerMath
. The example defines two operations with lambda expressions, addition
and subtraction
. The example prints the following:40 + 2 = 42
20 - 10 = 10
More examples and usages with new features of the java 8 on Lambda expressions will be discussed in my next posts. Thank you for reading this post.
No comments:
Post a Comment