Lambda expression
Bài đăng này đã không được cập nhật trong 3 năm
Lambda Expressions
A lambda (also known as closures) expression is like syntactic sugar for an anonymous class with one method whose type is inferred. It allows us to treat functionality as a method argument (passing functions around), or treat a code as data. Moreover, Lambda expression eliminates the need of anonymous class and gives a very simple yet powerful functional programming capability to Java.
A lambda is a code block which can be referenced and passed to another piece of code for future execution one or more times. Like functions, lambdas can be passed arguments at the time of their execution, modifying their results.
Syntax of lambda expression
parameters -> body
In its simplest form, a lambda could be represented as a comma-separated list of parameters, the –> symbol and the body.
Please notice the type of argument value is being inferred by the compiler. Alternatively, we can explicitly provide the type of the parameter, wrapping the definition in brackets like the following
Arrays.asList("apple", "mango", "orange")
.forEach((String value) -> System.out.println(value));
Several rules
When writing lambda expression, we should follow several important rules.
- Declaring the types of the parameters is optional. The compiler can inference the same from the value of the parameter.
- Using parentheses around the parameter is optional if we have only one parameter. For multiple parameters, parentheses are required.
- Using curly braces is optional (unless we need multiple statements).
- The return keyword is optional if we have a single expression that returns a value. The compiler automatically returns the value if the body has a single expression to return the value. Curly braces are required to indicate that expression returns a value.
Example
Lambdas may reference the class members and local variables (implicitly making them effectively final if they are not).
Here, though we didn’t declare separator variable as final, it will be implicitly final.
Return value from Lambda expression
Lambdas may return a value. The type of the return value will be inferred by compiler. The return statement is not required if the lambda body is just a one-liner. The two code snippets below are equivalent:
Arrays.asList( "a", "b", "d" ).sort( ( e1, e2 ) -> e1.compareTo( e2 ));
and
Arrays.asList( "a", "b", "d" ).sort( ( e1, e2 ) -> {
int result = e1.compareTo( e2 );
return result;
});
Here, the lambda expression implements the Comparator interface to sort strings by length.
Comparison of Java 8 to Java 7
Sorting a list of Strings
Let’s take another example
In Java 7, we sort the list by last-name and then first-name
Collections.sort(list, new Comparator<Person>() {
@Override
public int compare(Person p1, Person p2) {
int n = p1.getLastName().compareTo(p2.getLastName());
if (n == 0) {
return p1.getFirstName().compareTo(p2.getFirstName());
}
return n;
}
});
While in Java 8, this can be done as follows:
list.sort(Comparator.comparing(Person::getLastName)
.thenComparing(Person::getFirstName));
A simple demonstration
We will demonstrate a simple example so that we understand the concept of Lambda expression and in which case we should go with it.
Suppose, we have Employee class
Now, we want to search for employees who get salary greater than 50,000. For that, we will implement a method which will print filtered employee list.
public static void printHighlyPaidEmployee(List<Employee> employees, int salary) {
for (Employee employee : employees) {
if (employee.getSalary().intValue() >= salary) {
employee.printEmployee();
}
}
}
Now, if we have another filtering that have some search criteria’s that employee should match
public static void printSelectedEmployee(List<Employee> employees) {
for (Employee employee : employees) {
if (employee.getSalary().intValue() >= 40,000 &&
employee.getSalary().intValue() <= 70,000 &&
employee.getGender() == Employee.Sex.FEMALE) {
employee.printEmployee();
}
}
}
As, we have so many conditions to check, we will create a method to check all the conditions. We will create an interface with an abstract method and different classes which will implement that interface and implement the body of this abstract method according to their own requirement.
interface TestEmployee {
boolean test(Employee employee);
}
To use this class, you create a new instance of it and invoke the getEmployees method
getEmployees(employees, new EligibleEmployee());
We can use an anonymous class instead of a local class and bypass the need to declare a new class for each search.
Search Criteria Code in an Anonymous Class
Anonymous Classes enable us to implement a base class without giving it a name. Although this is often more concise than a named class, for classes with only one method, even an anonymous class seems a bit excessive and cumbersome.
getEmployees (
employees,
new TestEmployee() {
public boolean test(Employee employee) {
return employee. getSalary().intValue() >= 40,000 &&
employee.getSalary().intValue() <= 50,000 &&
employee.getGender() == Employee.Sex.FEMALE
}
}
);
This approach reduces the amount of code required because we don't have to create a new class for each search that we want to perform. However, the syntax of anonymous classes is bulky considering that the TestEmployee interface contains only one method.
Search Criteria Code with a Lambda Expression
Lambda expressions let us express instances of single-method classes more compactly.
The TestEmployee 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, we can omit the name of that method when we implement it. To do this, instead of using an anonymous class expression, we use a lambda expression, which is highlighted in the following method invocation:
getEmployees (
employees,
(Employee employee) -> employee. getSalary().intValue() >= 40,000 &&
employee.getSalary().intValue() <= 50,000 &&
employee.getGender() == Employee.Sex.FEMALE);
Using Aggregate Operations That accept Lambda Expressions as Parameters
employees
.stream()
.filter(
employee -> employee. getSalary().intValue() >= 40,000 &&
employee.getSalary().intValue() <= 50,000 &&
employee.getGender() == Employee.Sex.FEMALE)
.forEach(System.out.println(employee.getName());
All rights reserved