Lambda expressions are a new feature added in Java 8. Lambda expressions can simplify the traditional way of using Collections and the way of handling concurrency.
Lambda expression is a block of code that takes parameters, processes, and returns a value. It is similar to a function without a name. Lambda expressions can be embedded in the body of a method similar to a statement. It simplifies coding by introducing expression to represent a single method interface.
Functional Interface
To make use of lambda expressions, you have to use functional interfaces. You can either create your own functional interface or use pre-defined functional interfaces provided by Java.
Functional interfaces have only one method defined in their interface definition. Other examples of such interfaces are java.lang.Runnable, java.awt.event.ActionListener, java.util.Comparator, and java.util.concurrent.Callable. Functional interfaces are also called Single Abstract Method interfaces (SAM)
Let's take a look at a simple interface implementation to perform arithmetic operations on two arguments.
interface Abacus {
int operation(int a, int b);
}
Now let's take a look at lambda expressions that implement the above functional interface. When the method is called, the matching implementation will return the result of the mathematical operation.
public static void main(String args[]){
Abacus add = (int a, int b) -> a + b;
Abacus subtract = (a, b) -> a - b;
Abacus multiply = (int a, int b) -> { return a * b; };
Abacus divide = (int a, int b) -> a / b;
System.out.println(add.operation(1, 5));
System.out.println(subtract.operation(1, 5));
System.out.println(multiply.operation(1, 5));
System.out.println(divide.operation(1, 5));
}
The output would be the intended mathematical operation of two numbers. Although we implemented a simple calculation for demonstration purposes, real-world applications can contain fairly complex logic in place.
The output of the above code would look like:
6
-4
5
0
In addition to the single method declared in the interface, we can also declare the abstract methods inherited from the java.lang.Object class in the functional interface. The interface can be annotated with @FunctionalInterface for validation purposes. In the below, we implement toString() and equals() methods inherited from Object.
@FunctionalInterface
interface Abacus {
int operation(int a, int b);
public String toString();
public boolean equals(Object obj);
}
How to add custom methods to a functional interface?
If you want to add custom methods to the functional interface, you can use the default keyword to add any number of methods that are not abstract.
@FunctionalInterface
interface Abacus {
int operation(int a, int b);
public String toString();
public boolean equals(Object obj);
default int anotherAction(int a, int b){
return (a + b)*(a - b);
}
}
Sorting an array list with lambda
Let's take this array list and sort it both ways, traditional pre lambda code, and lambda code.
List letters = Arrays.asList("C", "B", "A", "E", "D");
Sorting without Lambda
Sorting an array list without lambda would involve an anonymous inner class. We use the inherited Object classes' compare method to compare each element in the array.
Collections.sort(letters, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
return o1.toString().compareTo(o2.toString());
}
});
Sorting with Lambda
We can utilize ArrayList's sort method in combination with lambda expressions to sort our list.
letters.sort((o1,o2) -> o1.toString().compareTo(o2.toString()));
Or Collection's sort method
Collections.sort(letters,(o1,o2) -> o1.toString().compareTo(o2.toString()));
Note that we have eliminated the anonymous inner class and the number of code lines is also reduced.