I'm liitFeet, a server-side engineer. Recently, I feel like Coroutine WebFlux with kotlin and Spring Boot. Coroutine difficult ...
This article is the 7th day of TeamLab Engineering Advent Calendar.
In this article, I'll explain how Java lambda expressions work. Eh, now? There is a feeling like that, but now that I can handle functions such as go and kotlin as first-class citizens, I thought that it seems that I'm actually using lambda expressions without knowing what they are.
In conclusion, java lambda expressions implement an interface with only one method to create an instance (new). I don't think you can understand anything in this explanation, so I will explain the process up to the lambda expression in order, using a program that displays the result of calculating a certain expression as an example.
I think it's easy to understand if you are aware that lambda expressions are easy to read for both humans and compilers while reducing the amount of description.
Also, this article describes the origin of Java lambda expressions, Please note that we will not explain the lambda expression itself in detail (if there is only one argument, you do not need to write parentheses, functional interface, etc.).
The source code can be found on GitHub.
First of all, I would like to realize a program that displays the calculated result by passing a normal class. The source code is normalClass package. There are four sources below.
Main.java main class
Display.java Class to display the calculation result
CalcuratorInterface.Interface defined for java computation
Display.java CalcuratorInterface
First, in the Display class, the calculator in charge of calculation and the value to be calculated (a, b) are received. Calculate and display the value of (a, b) with a calculator.
public class Display {
public void showCalc(CalculatorInterface calculator, int a, int b) {
System.out.println(calculator.calc(a, b));
}
}
CalculatorInterface defines calc, a method that performs calculations.
public interface CalculatorInterface {
int calc(int a, int b);
}
AddCalculator implements CalculatorInterface and returns the sum of the arguments (a, b).
public class AddCalculator implements CalculatorInterface {
@Override
public int calc(int a, int b) {
return a + b;
}
}
In the Main class, the calculation result is displayed by passing the calculated value to the Display class as `` `calculator```.
public class Main {
public static void main(String[] args) {
Display display = new Display();
CalculatorInterface calculator = new AddCalculator();
display.showCalc(calculator, 3, 5);
}
}
I think there is no particular problem.
Next, I would like to use the inner class. The source code is the innerClass package. CalcuratorInterface.java and Display.java are unchanged.
If you use the regular class mentioned above, don't you think it's a hassle to create a class file just for the addition that is used only for the Main class? Therefore, you can eliminate AddCalculator.java by defining AddCalculator in Main as shown below.
public class Main {
public static void main(String[] args) {
Display display = new Display();
//Define inner class
class AddCalculator implements CalculatorInterface {
@Override
public int calc(int a, int b) {
return a + b;
}
}
CalculatorInterface calculator = new AddCalculator();
display.showCalc(calculator, 3, 5);
}
}
Next, we will use the anonymous class. The source code is the anonymousInnerClass package. I didn't have to create one class file using the inner class, but if I only use it once here, I don't need to name this class. Therefore, let's implement the class on the spot at the timing of assigning it to the calculator.
public class Main {
public static void main(String[] args) {
Display display = new Display();
//Disposable once
CalculatorInterface calculator = new CalculatorInterface() {
@Override
public int calc(int a, int b) {
return a + b;
}
};
display.showCalc(calculator, 3, 5);
}
}
This is an anonymous class. It can't be reused, but the amount of description has gradually decreased.
Finally, pass arguments using a lambda expression.
The source code is lambdaExpression package.
By using an anonymous class, I was able to omit the name of the class and reduce the amount of description.
However, if you implement CalculatorInterface, it seems that the compiler will do it for you without writing `new CalculatorInterface ()`
.
Besides, if there is only one method, it is uniquely determined which method to implement.
Method arguments are also type-defined in the interface, and the compiler can infer the type without declaring it.
In a lambda expression, you can create an instance by writing only the methods required for implementation.
public class Main {
public static void main(String[] args) {
Display display = new Display();
//Only the processing of the method to be implemented
CalculatorInterface calculator = (a, b) -> {
return a + b;
};
display.showCalc(calculator, 3, 5);
}
}
The lambda expression is the following part. This part represents the implementation of the calc method of CalculatorInterface.
(a, b) -> {
return a + b;
};
(a, b)
Is an argument. I don't bother to write the method argument because the type is defined in the interface.
->
The following is the method implementation.a+b
Is returning.
What did you think. I hope you can understand the meaning of writing "java lambda expression implements an interface with only one method and creates an instance (new)" at the beginning!
It's a complete digression, but it would be nice to be able to handle functions as first-class citizens like kotlin ... the arguments are easy to understand ...
val calculator = {a: Int, b: Int -> a + b}
showCalc(calculator, 3, 5)
fun showCalc(calc: (Int, Int) -> Int, a: Int, b: Int) {
println(calc.invoke(a, b))
}
Recommended Posts