Ender Dincer
Nov 18, 2021
Java Lambda Expressions
Copy
1x -> {
2 return x + 5;
3}
Copy
1Output: -
Copy
1x -> x + 5
Copy
1Output: -
Copy
1Function<Integer, Integer> function = x -> x + 5;5
Copy
1Output: -
Copy
1public static void myMethod(Function<Integer, Integer> func){
2 //...
3}
4
5public static void main(String[] args){
6 // passing a lambda expression to method
7 myMethod(x -> x + 5);
8}
Copy
1Output: -
What makes this possible and what is "Function<Integer, Integer>" ? To understand lambda expressions in Java we need to understand how they are implemented with functional interfaces.
If an interface has only one abstract method, it is called a functional interface. A functional interface can have default methods (methods with bodies) but can not have multiple abstract methods.
Let's think of a simple example:
Copy
1interface Engine{
2 void start();
3}
4
5public class Car{
6 public string startCar(Engine engine){
7 engine.start();
8 return "Car ready to go!"
9 }
10}
Copy
1Output: -
Copy
1public class DieselEngine implements Engine{
2
3 @Override
4 public void start() {
5 System.out.println("Diesel engine starting...");
6 }
7}
Copy
1Output: -
Copy
1public class Race {
2
3 public static void main(String[] args) {
4 final Car dieselEngineCar = new Car(
5 new DieselEngine()
6 );
7
8 final Car petrolEngineCar = new Car(
9 new Engine() {
10 @Override
11 public void start() {
12 System.out.println("Petrol engine starting...");
13 }
14 }
15 );
16
17 final Car hybridEngineCar = new Car(
18 () -> System.out.println("Hybrid engine starting...")
19 );
20 }
21}
Copy
1Output: -
Copy
1final Engine hybridEngine =
2 () -> System.out.println("Hybrid engine starting...");
3
4final Car hybridEngineCar1 = new Car(hybridEngine);
5final Car hybridEngineCar2 = new Car(hybridEngine);
Copy
1Output: -
In most of the cases you will not have to write your own functional interface if you want use lambda expressions because there are already predefined functional interfaces in java.util.function package. Let's look at the most common ones.
Consumer Interface: Accepts a parameter but has no return type.
Copy
1@FunctionalInterface
2public interface Consumer<T> {
3 void accept(T t);
4 // other default methods...
5}
Copy
1Output: -
Copy
1x -> System.out.println(x)
Copy
1Output: -
Copy
1@FunctionalInterface
2public interface Supplier<T> {
3 T get();
4 // other default methods...
5}
Copy
1Output: -
Copy
1() -> Math.random()
Copy
1Output: -
Copy
1@FunctionalInterface
2public interface Predicate<T> {
3 boolean test(T t);
4 // other default methods...
5}
Copy
1Output: -
Copy
1x -> (x == 1) ? true : false
Copy
1Output: -
Copy
1@FunctionalInterface
2public interface Function<T, R> {
3 R apply(T t);
4}
Copy
1Output: -
Copy
1x -> x * 5
Copy
1Output: -
These are the main functional interfaces. There are many more, for multiple input parameters, for primitive types etc. Of course you can create your own functional interface and use it as a lambda if you like as long as your interface has only one abstract method!
Like a method can throw an exception a lambda can too. The only restriction is that the exception (if it's a checked exception) should match the throws clause of the abstract method the lambda overriding.
Happy coding!