A new grammar introduced in Java 8. Simplify the processing description by omitting the contents to be described using the local class and the anonymous class. As typical examples, the methods of Collections.sort and Stream API have benefited.
Lambda expressions use a mechanism called local classes and anonymous classes.
A local class is a mechanism that can be used by declaring a class during method processing.
public static void main(String[] args) {
class Local {
public void sayHello() {
System.out.println("Hello!");
}
}
Local local = new Local();
local.sayHello(); // Hello!
}
You can also define a local class that implements the interface.
public static void main(String[] args) {
class Local implements Runnable {
@Override
public void run() {
System.out.println("Hello Lambda!");
}
}
Runnable runner = new Local();
runner.run(); // Hello Lambda!
}
Next, let's take a look at the anonymous class.
Anonymous class is a mechanism that omits the declaration of the local class that implements the interface. Here is an example of an anonymous class that implements the Runnable interface.
public static void main(String[] args) {
Runnable runner = new Runnable() {
@Override
public void run() {
System.out.println("Hello Lambda!");
}
};
runner.run(); //Hello Lambda!
}
It looks as if you are instantiating the Rannable interface, but you are actually creating an instance of an anonymous class that implements the Rannable interface. Finally, let's take a look at the lambda expression.
It becomes a lambda expression by omitting "new Runnable () {}" and "public void run" from the anonymous class.
public static void main(String[] args) {
Runnable runner = () -> { System.out.println("Hello Lambda!"); };
runner.run(); //Hello Lambda!
}
The first () represents the argument of the run method, and the contents of-> {} are the implementation contents of the run method. An instance of an anonymous class that implements Runnable is assigned to the runner variable. In other words, a lambda expression is an expression that creates an instance that implements the interface.
By the way, if you omit "new Runnable () {}", you don't know what type of instance to create. In Java, it is a mechanism to infer automatically according to the type of the variable to be assigned. This mechanism is called type inference.
Also, if you omit "public void run", you won't know which method to override for an interface that has multiple methods defined. Therefore, a lambda expression can only use an interface with one abstract method.
Only the Rannable interface can create lambda expressions with no arguments and no return value. If you want to create it in another form, a functional interface has been added, so use that.
A functional interface is an interface that can be assigned to a lambda expression or method reference.
The condition of a functional interface is, roughly speaking, an interface that has only one abstract method defined. Static methods and default methods can be included (ignored as a condition of functional interfaces). Also, if a public method in the Object class is defined as an abstract method in the interface, that method is also ignored. (Interfaces that meet this condition are now called "functional interfaces" in JDK 1.8)
A lot of interfaces have been added under the java.util.function package from SE8. https://docs.oracle.com/javase/jp/8/docs/api/java/util/function/package-summary.html
This time, I will introduce the interface that I often use.
2-1. Function<T, R> Function is a functional interface for converting values. In Function \ <T, R>, T specifies the method argument type, and R specifies the return type. Takes an argument, converts (calculates) it, and returns another value. The method is R apply (T).
Function<Integer, String> asterisker = (i) -> { return "*"+ i; };
String result = asterisker.apply(10);
System.out.println(result); // *10
2-2. Consumer<T>
Consumer is a functional interface for receiving arguments and using them for processing.
T in Consumer \
Consumer<String> buyer = (goods) -> { System.out.println(goods + "I bought"); };
buyer.accept("rice ball"); // rice ballを購入しました。
2-3. Predicate<T>
Predicate is a functional interface for making judgments.
T in Predicate \
Predicate<String> checker = (s)-> { return s.equals("Java"); };
boolean result = checker.test("Java");
System.out.println(result); //true
The following code describes the Stream API using a lambda expression.
List<Integer> numbers = List.of(3, 1, -4, 1, -5, 9, -2, 6, 5, 3, 5);
numbers.stream()
.filter(number -> Math.abs(number) >= 5)
.forEach(System.out::println);
The output result is as follows.
-5
9
6
5
5
Next, let's take a look at the code written without using a lambda expression.
List<Integer> numbers = List.of(3, 1, -4, 1, -5, 9, -2, 6, 5, 3, 5);
numbers.stream()
.filter(new Predicate<Integer>() {
@Override
public boolean test(Integer number) {
return Math.abs(number) >= 5;
}
})
.forEach(new Consumer<Integer>() {
@Override
public void accept(Integer number) {
System.out.println(number);
}
});
As introduced in the decomposition of lambda expression, the method description to generate and execute the interface is increasing, so The amount of code written has increased and the processing outlook has become very poor. In this way, it is used to make the processing description concise and easy to understand.
Explains the grammar of lambda expressions. Below is the basic grammar of a lambda expression.
(argument) -> {processing; }
The following is written according to this grammar.
// (1)If there are arguments and a return value
(Integer number) -> {
return Math.abs(number) >= 5;
}
// (2)If there is no return value
(Integer number) -> {
System.out.println(number);
}
// (3)If there are no arguments or return values
() -> {
System.out.println("Hello!");
}
(1) is an example that has an argument and a return value like Predicate. Processing is performed using the number specified by the argument, and the return value is returned. (2) is an example where there is no return value like Consumer. In that case, there is no need to write a return statement. For processing without arguments as in (3), describe the argument part in (). For example, java.lang.Runnable.
You can also omit the argument type in a lambda expression. And you can omit the parentheses () around the argument only if you have only one argument. It cannot be omitted if there is no argument or if there are two or more. Applying this rule to (1) and (3) gives:
// (1)Because it has one argument( )Can be omitted
number -> {
return Math.abs(number) >= 5;
}
// (3)Because there are no arguments( )Cannot be omitted
() -> {
System.out.println("Hello!");
}
In addition, if there is only one line, you can omit the curly braces {}, return, and the semicolon at the end of the sentence. The abbreviations for (1) to (3) are as follows.
// (1)If there are arguments and a return value
number -> Math.abs(number) >= 5
// (2)If there is no return value
number -> System.out.println(number)
// (3)If there are no arguments or return values
() -> System.out.println("Hello!")
Finally, the argument itself can be omitted by using the method reference only when the processing content is one method call and the argument is uniquely determined. The method reference has the following syntax.
name of the class::Method name
This method reference can only be applied in (2). If (2) is described using the method reference, it will be as follows.
System.out::println
The System.out.println method is a method that takes only one argument, and it is clear that the value of the argument Integer is passed, so a method reference is available. On the other hand, in (1), the method reference cannot be used because there is a magnitude judgment of> = 5 after the method call. Also, in (3), since the value "Hello!" Is specified for the argument, it cannot be said that the argument is uniquely determined, and the method reference cannot be used for this either.
With this in mind, let's take a look at the stream processing earlier.
List<Integer> numbers = List.of(3, 1, -4, 1, -5, 9, -2, 6, 5, 3, 5);
numbers.stream()
.filter(number -> Math.abs(number) >= 5)
.forEach(System.out::println);
You can see that the lambda expression learned in (1) and (2) is embedded in the streamAPI.
Understanding Java 8 Lambda Expressions Modern Java Learned with Lambda Expressions and Stream APIs-The Present of the Java Language Changing with Functionals
Recommended Posts