We will start with What Lambda expressions are, syntax for lambda expressions, defining no paramter/ single or multi parameter lambda expressions, return value from Lambda expressions, accessing local variables from Lambda expressions and end the post with target typing in lambda expressions.
Lambda expressions are the first step of Java towards functional programming. Lambda expressions enable us to treat functionality as method arguments, express instances of single-method classes more compactly.
Lambda has three parts:
(param) -> { System.out.println(param); }
Lambda expression can only be used where the type they are matched are functional interfaces.
If the lambda expression is matching against no parameter method, it can be written as:
() -> System.out.println("No paramter expression");
If lambda expression is matching against method which take one or more parameter, it can be written as:
(param) -> System.out.println("Single param expression: " + param);
(paramX, paramY) -> System.out.println("Two param expression: " + paramX + ", " + paramX);
You can also define the type of parameter in Lambda expression.
(Employee e) -> System.out.println(e);
You can return value from lambda just like a method did.
(param) -> {
// perform some steps
return "some value";
};
In case lambda is performing single step and returning value. Then you can write it as:
//either
(int a, int b) -> return Integer.compare(a, b);
// or simply lambda will automatically figure to return this value
(int a, int b) -> Integer.compare(a, b);
Lambda can access the final or effectively final variables of the method in which they are defined. They can also access the instance variables of enclosing class.
You might have seen in earlier code snippets that we have omitted the type of parameter, return value and the type of Lambda. Java compiler determines the target type from the context lambda is defined.
Compiler checks three things:
Now, Let's jump to an example to verify it.
@FunctionalInterface
interface InterfaceA {
void doWork();
}
@FunctionalInterface
interface InterfaceB<T> {
T doWork();
}
class LambdaTypeCheck {
public static void main (String[] args) {
LambdaTypeCheck typeCheck = new LambdaTypeCheck();
typeCheck.invoke(() -> "I am done with you");
}
public <T> T invoke (InterfaceB<T> task) {
return task.doWork();
}
public void invoke (InterfaceA task) {
task.doWork();
}
}
When you call typeCheck.invoke(() -> "I am done with you");
then invoke (InterfaceB<T> task)
will be called. Because the lambda return value which is matched by InterfaceB<T>
.