Lambdas offer a concise way to define anonymous methods in Java, i.e. methods not requiring to be part of a class definition and object instantiations.
You can assign these methods to variables and pass these variables around just like one might do in python or JS!
Here is how:
We all know how to define a method:
Integer (Integer x) {return x * 2;}
A lambda function however can be shortened as Java now has type inference for Lambda functions! All you need is an arrow! And this can be done inline.
MyJavaFunction function = (x) -> {
return x * 2;
}
This can be shortened even more to this if it is a single line of code.
MyJavaFunction function = x -> x * 2;
But what is MyJavaFunction?
public class Main {
public static void main(String[] args) {
// creating a lambda
MyJavaFunction myJavaFunction = x -> x * 2;
// running the method
System.out.println(myJavaFunction.doStuff(4));
}
// Java uses interfaces to make lambdas possible
interface MyJavaFunction {
Integer doStuff(Integer x);
}
}
It's just a faster way to create "Functions" without needing an explicit class.
These lambda functions can be created only as Single Abstract Method (SAM) interfaces.
That is you can define one method inside an interface and create any kind of implementation as long as you stick to the structure of that abstract method.
public class Main {
public static void main(String[] args) {
//The below won't work since Multiply1Number isn't a SAM!
//Multiply1Number lambdaFunction = x -> x * 2;
// This is a SAM. This will get instantiated :)
Multiply2Numbers lambdaFunction = (x , y) -> x * y;
}
interface Multiply1Number {
Integer doStuff(Integer x);
//adding a second method won't let you create lambdas as this isn't SAM
Integer multiply(Integer x , Integer y);
}
/**be sure to add the below annotation in order to restrict
the interface to just be a SAM interface.
*/
@FunctionalInterface
interface Multiply2Numbers {
// create a seperate SAM if you need a different signature
Integer multiply(Integer x, Integer y);
}
}
Lambdas makes it incredibly easy to reuse an interface on the fly.
public class Main {
public static void main(String[] args) {
// you can create any type of computer
Computer substraction = (x , y) -> x - y;
Computer multiply = (x , y) -> x * y;
Computer addition = (x , y) -> x + y;
// You can implement your printer to take in any kind of computer
Printer printer = (computer, x, y) -> System.out.println(computer.compute(x, y));
// You can pass your lambda to other lambdas
printer.print(addition, 1, 1);
printer.print(substraction, 1, 1);
}
@FunctionalInterface
interface Computer {
Integer compute(Integer x, Integer y);
}
@FunctionalInterface
interface Printer {
void print(Computer computer, int x, int y);
}
}
"Functional programming" as we call this approach is in many ways quite distinct from traditional Object Oriented Programming and we will be looking at this more in my next blog post!