Recently, I’ve had time to review some of the JDK8 features, which are becoming more and more important in actual development. This article focuses on Lambda expressions
Lambda expressions
Lambda expressions, also known as closures, are the most important new feature driving the release of Java 8. Lambda allows functions to be passed as arguments to a method. Using Lambda expressions can make the code more compact.
1. Demand analysis
Create a new thread and specify the tasks to be performed by the thread
public static void main(String[] args) {
// Start a new thread
new Thread(new Runnable() {
@Override
public void run(a) {
System.out.println("Code executed in a new thread:"+Thread.currentThread().getName());
}
}).start();
System.out.println(Code in the main thread: + Thread.currentThread().getName());
}
Copy the code
Code analysis:
- The Thread class takes a Runnable interface as an argument, where the abstract run method is used to specify the core of the Thread’s task content
- To specify the body of the run method, you need a Runnable implementation class
- In order to avoid defining an implementation class for Runnable, you have to use anonymous inner classes
- The abstract run method must be overridden. All the method names, parameters, and return values must be overridden without error.
- In fact, we only care about the code in the method body
Let’s advance: 463257262
2. Initial experience of Lambda expressions
A Lambda expression is an anonymous function that can be understood as a piece of code that can be passed
new Thread(() -> { System.out.println("New thread Lambda expression..." +Thread.currentThread().getName()); })
.start();
Copy the code
Advantages of Lambda expressions: Simplified use of anonymous inner classes, simpler syntax.
After experimenting with Lambda expressions, Lambda expressions are a way to simplify anonymous inner classes because of their syntactic redundancy.
3. Grammar rules for Lambda
Lambdas dispense with object-oriented conventions, and the standard Lambda format consists of three parts:
(parameter type parameter name) -> {code body; }Copy the code
Format description:
- (Parameter type Parameter name): parameter list
- {code body; } : method body
- -> : Arrow to separate the parameter list from the method body
3.1 Lambda Exercise 1
Exercise lambdas with no arguments and no return values
Define an interface
public interface UserService {
void show(a);
}
Copy the code
Then create the main method to use
public class Demo03Lambda {
public static void main(String[] args) {
goShow(new UserService() {
@Override
public void show(a) {
System.out.println("The show method executes..."); }}); System.out.println("-- -- -- -- -- -- -- -- -- --");
goShow(() -> { System.out.println("The Lambda show method executes..."); });
}
public static void goShow(UserService userService){ userService.show(); }}Copy the code
Output:
The show method executes... ---------- Lambda show method executes...Copy the code
3.2 Lambda Exercise 2
Complete a case that takes arguments and has a return worthy Lambda expression
Create a Person object
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
private String name;
private Integer age;
private Integer height;
}
Copy the code
Then we store multiple Person objects in the List collection, and we sort those objects by age
public static void main(String[] args) {
List<Person> list = new ArrayList<>();
list.add(new Person("Jay Chou".33.175));
list.add(new Person("Andy Lau".43.185));
list.add(new Person("Stephen Chow".38.177));
list.add(new Person(Aaron Kwok.23.170));
Collections.sort(list, new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
returno1.getAge()-o2.getAge(); }});for(Person person : list) { System.out.println(person); }}Copy the code
We find that the second argument in the sort method is an anonymous inner class of the Comparator interface, and the method that executes has parameters and return values, so we can rewrite this as a Lambda expression
public static void main(String[] args) {
List<Person> list = new ArrayList<>();
list.add(new Person("Jay Chou".33.175));
list.add(new Person("Andy Lau".43.185));
list.add(new Person("Stephen Chow".38.177));
list.add(new Person(Aaron Kwok.23.170));
/*Collections.sort(list, new Comparator
() { @Override public int compare(Person o1, Person o2) { return o1.getAge()-o2.getAge(); }}); for (Person person : list) { System.out.println(person); } * /
System.out.println("-- -- -- -- -- -");
Collections.sort(list,(Person o1,Person o2) -> {
return o1.getAge() - o2.getAge();
});
for(Person person : list) { System.out.println(person); }}Copy the code
The output
Person(name= kwok, age=23, height=170) Person(name= Kwok, age=23, height=170) Person(name= Kwok, age=33, height=175) Person(name= kwok, age=33, height=175) Height =177) Person(name= Lau, age=43, height=185)Copy the code
4. @ FunctionalInterface annotation
The @functionalInterface annotation is a new functional annotation in JDK8, indicating that the interface modified by the annotation can only have one abstract method.
/ * * *@FunctionalInterface* This is a functional annotation. An interface decorated by this annotation can only declare one abstract method */
@FunctionalInterface
public interface UserService {
void show(a);
}
Copy the code
5. The principle of Lambda expressions
The essence of anonymous inner classes is to generate a Class file at compile time. XXXXX$1.class
public class Demo01Lambda {
public static void main(String[] args) {
// Start a new thread
new Thread(new Runnable() {
@Override
public void run(a) {
System.out.println("Code executed in a new thread:"+Thread.currentThread().getName());
}
}).start();
System.out.println(Code in the main thread: + Thread.currentThread().getName());
System.out.println("-- -- -- -- -- -- -- -- -- -- -- -- -- -- --");
/*new Thread(() -> {system.out.println (" new Thread..."); +Thread.currentThread().getName()); }) .start(); * /}}Copy the code
You can also view the generated code with the XJad tool by decompiling the tool
static class Demo01LambdaThe $1implements Runnable
{
public void run(a)
{
System.out.println((new StringBuilder()).append("Code executed in a new thread:" ).append(Thread.currentThread().getName()).toString());
}
Demo01Lambda$1() {}}Copy the code
So how do Lambda expressions work? We also used a decompile tool to look at itThe class file with a Lambda expression is written, and we see the error from XJad. At this point, we can disassemble the bytecode using a tool that comes with the JDK: JavAP.
Javap -c -p File name class -c: disassembles code. -p: displays all classes and membersCopy the code
The result of disassembly:
E:\workspace\OpenClassWorkSpace\JDK8Demo\target\classes\com\bobo\jdk\lambda>javap -c -p Demo03Lambda.class Compiled from "Demo03Lambda.java" public class com.bobo.jdk.lambda.Demo03Lambda { public com.bobo.jdk.lambda.Demo03Lambda(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: invokedynamic #2, 0 // InvokeDynamic #0:show:()Lcom/bobo/jdk/lambda/service/UserService; 5: invokestatic #3 // Method goShow:(Lcom/bobo/jdk/lambda/service/UserService;) V 8: return public static void goShow(com.bobo.jdk.lambda.service.UserService); Code: 0: aload_0 1: invokeinterface #4, 1 // InterfaceMethod com/bobo/jdk/lambda/service/UserService.show:()V 6: return private static void lambda$main$0(); Code: 0: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream; 3: LDC #6 // String Lambda 5: invokevirtual #7 // Method java/io/PrintStream.println:(Ljava/lang/String;) V 8: return }Copy the code
In the decompiled source code we see a static method lambda
0(), what’s going on in this method? Let’s debug it to see:
The above effect can be interpreted as follows:
public class Demo03Lambda {
public static void main(String[] args) {... }private static void lambda$main$0(a); System.out.println("The Lambda show method executes..."); }}Copy the code
In order to more intuitive understanding of the content, we can add at run – Djdk. Internal. Lambda. DumpProxyClasses, add this parameter to output the internal class code to a file
Java - Djdk. Internal. Lambda. DumpProxyClasses to run the package name. The name of the classCopy the code
Command execution
E:\workspace\OpenClassWorkSpace\JDK8Demo\target\classes>java -Djdk.internal.lambda.dumpProxyClasses Com. Bobo. JDK. Lambda. Demo03Lambda lambda show method carried out...Copy the code
Decompiled content:
You can see that this anonymous inner class implements the UserService interface and overwrites the show() method. Demo03lambda.lambda mainmain0() is called in the show method, which is what is in the lambda.
public class Demo03Lambda {
public static void main(String[] args) {
goShow(new UserService() {
@Override
public void show(a) {
Demo03Lambda.lambda$main$0();
}
});
System.out.println("-- -- -- -- -- -- -- -- -- --");
}
public static void goShow(UserService userService){
userService.show();
}
private static void lambda$main$0(a); System.out.println("The Lambda show method executes..."); }}Copy the code
Summary:
Anonymous inner classes generate a class file when compiled.
Lambda expressions form a class while the program is running.
- A method has been added to the class whose method body is the code in the Lambda expression
- It also forms an anonymous inner class that implements the interface and overrides abstract methods
- Overwriting a method in an interface calls the newly generated method
6. Omission of Lambda expressions
Based on the standard method of writing lambda expressions, the rules for using ellipsis are:
- Parameter types in parentheses can be omitted
- If there is only one argument in parentheses, the parentheses can be omitted
- If there is only one statement in braces, omit braces, the return keyword, and the statement semicolon.
public class Demo05Lambda {
public static void main(String[] args) {
goStudent((String name,Integer age)->{
return name+age+"6666...";
});
// Omit to write
goStudent((name,age)-> name+age+"6666...");
System.out.println("-- -- -- -- -- -");
goOrder((String name)->{
System.out.println("- >" + name);
return Awesome!;
});
// Omit to write
goOrder(name -> {
System.out.println("- >" + name);
return Awesome!;
});
goOrder(name -> Awesome!);
}
public static void goStudent(StudentService studentService){
studentService.show("Zhang".22);
}
public static void goOrder(OrderService orderService){
orderService.show("Bill"); }}Copy the code
7. Prerequisites for use of Lambda expressions
The syntax of Lambda expressions is very concise, but Lambda expressions are not to be used lightly, and there are several conditions that should be taken into account when using them
- The parameter or local variable type of a method must be an interface to use a Lambda
- There is one and only one abstract method in the interface (@functionalInterface)
8.Lambda versus anonymous inner classes
Lambda versus anonymous inner classes
-
The required types are different
- The types of anonymous inner classes can be classes, abstract classes, or interfaces
- The type required for a Lambda expression must be an interface
-
The number of abstract methods is different
- The number of abstract methods in the interface required for an anonymous inner class is arbitrary
- There can only be one abstract method in the interface required for a Lambda expression
-
The implementation principle is different
- Anonymous inner classes are compiled to form a class
- Lambda expressions generate classes dynamically while the program is running
~ Well, the content of Lambda expression is introduced here, if it is helpful to you, welcome to like and collect oh V_V