Recently I just had time to sort out the JDK8 features, which are becoming more and more important in the actual development. In this article, I will focus on Lambda expressions

Lambda expressions

Lambda expressions, also known as closures, are the most important new feature driving the Java 8 release. Lambda allows functions to be passed as arguments to a method. Lambda expressions can make code much more compact.

1. Requirements analysis

Creates a new thread, specifying 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 new thread:"+Thread.currentThread().getName());
            }
        }).start();
        System.out.println("Code in main thread:" + Thread.currentThread().getName());
    }
Copy the code

Code analysis:

  1. The Thread class takes a Runnable interface as a parameter, where the abstract run method is used to specify the core of the Thread’s task content
  2. In order to specify the body of the Run method, you have to require an implementation class of Runnable
  3. To avoid having to define a Runnable implementation class, anonymous inner classes have to be used
  4. The abstract run method has to be overridden. All method names, method parameters, and method return values have to be overridden without error.
  5. In fact, we only care about the code in the method body

2. Initial experience with 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 and simpler syntax.

Anonymous inner classes have syntax redundancy, and after experimenting with Lambda expressions, Lambda expressions are a way to simplify anonymous inner classes.

3. Grammar rules for Lambda

The standard format of Lambda is composed 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, split argument list and method body

3.1 Lambda Exercise 1

Practice Lambda with no parameters and no return value

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("Show method executed..."); }}); System.out.println("-- -- -- -- -- -- -- -- -- --");
        goShow(() -> { System.out.println("Lambda show method executes..."); });
    }

    public static void goShow(UserService userService){ userService.show(); }}Copy the code

Output:

The show method executes... The ---------- Lambda show method executes...Copy the code

3.2 Lambda Exercise 2

Complete the case of a Lambda expression that takes a reference and returns a Lambda worthy expression

Create a Person object

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {

    private String name;

    private Integer age;

    private Integer height;

}

Copy the code

We then store multiple Person objects in the List collection and sort them 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 to the sort method is an anonymous inner class of the Comparator interface, and that the method is executed with arguments and return values, so we can rewrite it 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=33, height=170) Person(name= kwok, age=33, height=175) Height =177) Person(name= height, age=43, height=185)Copy the code

4. @ FunctionalInterface annotation

@functionalInterface is a new functional annotation in JDK8 that indicates that the interface that the annotation modifies can have only one abstract method.

/ * * *@FunctionalInterface* This is a functional annotation that modifies an interface to declare only one abstract method */
@FunctionalInterface
public interface UserService {

    void show(a);

}
Copy the code

5. How Lambda expressions work

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 new thread:"+Thread.currentThread().getName());
            }
        }).start();
        System.out.println("Code in main thread:" + Thread.currentThread().getName());
        System.out.println("-- -- -- -- -- -- -- -- -- -- -- -- -- -- --");
        /*new Thread(() -> {system.out.println (" new Thread Lambda expression... +Thread.currentThread().getName()); }) .start(); * /}}Copy the code

You can also view the generated code using the decompile tool, the XJad tool

static class Demo01LambdaThe $1implements Runnable
{

	public void run(a)
	{
		System.out.println((new StringBuilder()).append("Code executed in new thread:" ).append(Thread.currentThread().getName()).toString());
	}

	Demo01Lambda$1() {}}Copy the code

So how does a Lambda expression work? We also looked at it with a decompiler toolWrite a class file with Lambda expressions, we use XJad to check the error. In this case, we can disassemble bytecode through a tool that comes with JDK: Javap.

Javap -c -p File name Class -c: disassembler code -p: displays all classes and membersCopy the code

Disassembly results:

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 show method executes... 5: invokevirtual #7 // Method java/io/PrintStream.println:(Ljava/lang/String;) V 8: return }Copy the code

In this decompiled source we see a static method lambda
m a i n main
Zero of alpha, what’s going on in this method? Let’s check it by means of debug:

The above effect can be understood as follows:

public class Demo03Lambda {

    public static void main(String[] args) {... }private static void lambda$main$0(a); System.out.println("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. The show method calls demo03lambda.lambda mainmainmain0(), which calls the contents of 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("Lambda show method executes..."); }}Copy the code

Summary:

Anonymous inner classes generate a class file when compiled.

Lambda expressions form a class when the program is run.

  1. A new method is added to the class whose method body is the code in the Lambda expression
  2. It also forms an anonymous inner class that implements interfaces and overrides abstract methods
  3. Overriding a method in an interface invokes the newly generated method

6. Ellipsis of Lambda expressions

Based on the standard way of writing lambda expressions, the rules for ellipsis are as follows:

  1. Parameter types in parentheses can be omitted
  2. If there is only one argument in the parentheses, the parentheses can be omitted
  3. If there is only one statement in the braces, you can omit the braces, return keyword, and statement semicolon.
public class Demo05Lambda {

    public static void main(String[] args) {
        goStudent((String name,Integer age)->{
            return name+age+"6666...";
        });
        //
        goStudent((name,age)-> name+age+"6666...");
        System.out.println("-- -- -- -- -- -");
        goOrder((String name)->{
            System.out.println("- >" + name);
            return Awesome!;
        });
        //
        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. The 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 to pay attention to when using them

  1. To use a Lambda, the parameter or local variable type of a method must be an interface
  2. One and only abstract method in the interface (@functionalInterface)

8.Lambda versus anonymous inner classes

Lambda versus anonymous inner classes

  1. The required type is different

    • The types of anonymous inner classes can be classes, abstract classes, interfaces
    • The type required for Lambda expressions must be interfaces
  2. The number of abstract methods varies

    • The number of abstract methods in the interface required by an anonymous inner class is arbitrary
    • Only one abstract method can exist in the interface required for a Lambda expression
  3. The implementation principle is different

    • Anonymous inner classes are compiled to form a class
    • Lambda expressions generate classes dynamically at runtime

~ well, Lambda expression content is introduced here, if you are helpful, welcome to like attention plus favorites oh V_V