As an experienced programmer, if you don’t understand Lambda expressions, you can’t justify it. Collect it! ! !

Recently, I just have time to sort out the features of JDK8 for everyone. This role in actual development is getting more and more important. This article focuses on Lambda expressions.

Lambda expression

Lambda expressions, also known as closures, are the most important new features that promote the release of Java 8.
Lambda allows a function to be used as a method parameter (a function is passed into the method as a parameter).
Using Lambda expressions can make the code more concise and compact.

1. Demand analysis

Create a new thread, specify the task to be performed by the thread

    public static void main(String[] args) {
        // 开启一个新的线程
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("新线程中执行的代码 : "+Thread.currentThread().getName());
            }
        }).start();
        System.out.println("主线程中的代码:" + Thread.currentThread().getName());
    }

Code analysis:

  1. The Thread class requires a Runnable interface as a parameter, the abstract method run method is used to specify the core of the thread task content
  2. In order to specify the body of the run method, the implementation class of Runnable has to be required
  3. In order to save the need to define a Runnable implementation class, anonymous inner classes have to be used
  4. The abstract run method must be rewritten. All method names, method parameters, and method return values ​​have to be rewritten again, and no errors can be made.
  5. In fact, we only care about the code in the method body

2. First experience of Lambda expression

Lambda expression is an anonymous function, which can be understood as a piece of code that can be passed

new Thread(() -> { System.out.println("新线程Lambda表达式..." +Thread.currentThread().getName()); })
                .start();

Advantages of lambda expressions: simplifies the use of anonymous inner classes, and the syntax is simpler.

The syntax of anonymous inner classes is redundant. After experiencing Lambda expressions, I found that Lambda expressions are a way to simplify anonymous inner classes.

3. Lambda's grammar rules

Lambda eliminates the object-oriented rules and regulations. The standard format of Lambda consists of 3 parts:

(参数类型 参数名称) -> {
    代码体;
}

Format description:

  • (Parameter type parameter name): parameter list
  • {Code body;}: method body
  • ->: Arrow, split parameter 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();
}

Then create the main method using

public class Demo03Lambda {

    public static void main(String[] args) {
        goShow(new UserService() {
            @Override
            public void show() {
                System.out.println("show 方法执行了...");
            }
        });
        System.out.println("----------");
        goShow(() -> { System.out.println("Lambda show 方法执行了..."); });
    }

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

Output:

show 方法执行了...
----------
Lambda show 方法执行了...

3.2 Lambda exercise 2

Complete a Lambda expression case with parameters and return value

Create a Person object

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {

    private String name;

    private Integer age;

    private Integer height;

}

Then we save multiple Person objects in the List collection, and then sort these objects according to age

    public static void main(String[] args) {
        List<Person> list = new ArrayList<>();
        list.add(new Person("周杰伦",33,175));
        list.add(new Person("刘德华",43,185));
        list.add(new Person("周星驰",38,177));
        list.add(new Person("郭富城",23,170));

        Collections.sort(list, new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                return o1.getAge()-o2.getAge();
            }
        });
        for (Person person : list) {
            System.out.println(person);
        }
    }

We found that the second parameter of the sort method is an anonymous inner class of the Comparator interface, and the executed method has parameters and return values, then we can rewrite it as a Lambda expression

    public static void main(String[] args) {
        List<Person> list = new ArrayList<>();
        list.add(new Person("周杰伦",33,175));
        list.add(new Person("刘德华",43,185));
        list.add(new Person("周星驰",38,177));
        list.add(new Person("郭富城",23,170));

        /*Collections.sort(list, new Comparator<Person>() {
            @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);
        }
    }

Output result

Person(name=郭富城, age=23, height=170)
Person(name=周杰伦, age=33, height=175)
Person(name=周星驰, age=38, height=177)
Person(name=刘德华, age=43, height=185)

4. @FunctionalInterface annotation

@FunctionalInterface is a newly added functional annotation in JDK8, which means that the interface modified by this annotation can only have one abstract method.

/**
 * @FunctionalInterface
 *    这是一个函数式注解,被该注解修饰的接口只能声明一个抽象方法
 */
@FunctionalInterface
public interface UserService {

    void show();

}

5. Principles 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) {
        // 开启一个新的线程
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("新线程中执行的代码 : "+Thread.currentThread().getName());
            }
        }).start();
        System.out.println("主线程中的代码:" + Thread.currentThread().getName());
        System.out.println("---------------");
        /*new Thread(() -> { System.out.println("新线程Lambda表达式..." +Thread.currentThread().getName()); })
                .start();*/
    }
}
Insert picture description here

You can also use the decompiler tool to view the generated code XJad tool to view

static class Demo01Lambda$1
	implements Runnable
{

	public void run()
	{
		System.out.println((new StringBuilder()).append("新线程中执行的代码 : " ).append(Thread.currentThread().getName()).toString());
	}

	Demo01Lambda$1()
	{
	}
}

So what is the principle of Lambda expressions? We also use the decompiler tool to view

Insert picture description here


the class file written with Lambda expressions, and we use XJad to view the error. At this time, we can use a tool that comes with the JDK: javap to disassemble the bytecode.

javap -c -p 文件名.class

-c:表示对代码进行反汇编
-p:显示所有的类和成员

The result of the 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 show 方法执行了...
       5: invokevirtual #7                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       8: return
}

In this decompiled source code, we see a static method lambda$main$0(). What does this method do? Let's check through debug:

Insert picture description here

The above effect can be understood as follows:

public class Demo03Lambda {

    public static void main(String[] args) {
        ....
    }

    private static void lambda$main$0();
        System.out.println("Lambda show 方法执行了...");
    }
}

In order to understand this content more intuitively, we can add -Djdk.internal.lambda.dumpProxyClasses at runtime, adding this parameter will output the internal class code to a file

java -Djdk.internal.lambda.dumpProxyClasses 要运行的包名.类名

Command execution

E:\workspace\OpenClassWorkSpace\JDK8Demo\target\classes>java -Djdk.internal.lambda.dumpProxyClasses com.bobo.jdk.lambda.Demo03Lambda
Lambda show 方法执行了...
Insert picture description here


Content after decompilation:

Insert picture description here

You can see that this anonymous inner class implements the UserService interface and overrides the show() method. Demo03Lambda.lambda$main$0() is called in the show method, that is, the content in Lambda is called.

public class Demo03Lambda {

    public static void main(String[] args) {
        goShow(new UserService() {
            @Override
            public void show() {
                Demo03Lambda.lambda$main$0();
            }
        });
        System.out.println("----------");
       
    }

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

    private static void lambda$main$0();
        System.out.println("Lambda show 方法执行了...");
    }
}

summary:

An anonymous inner class will generate a class file when it is compiled.

Lambda expressions will form a class when the program is running.

  1. A new method is added to the class. The method body of this method is the code in the Lambda expression
  2. It will also form an anonymous inner class, implement interfaces, and override abstract methods
  3. Overriding the method in the interface will call the newly generated method

6. The omission of Lambda expressions

Based on the standard way of writing lambda expressions, the rules that can be used to omit the way of writing are:

  1. The parameter types in parentheses can be omitted
  2. If there is only one parameter in the parentheses, the parentheses can be omitted
  3. If there is one and only one statement in the braces, you can omit the braces, the return keyword, and the statement semicolon at the same time.
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 666;
        });
        // 省略写法
        goOrder(name -> {
            System.out.println("--->" + name);
            return 666;
        });
        goOrder(name ->  666);
    }

    public static void goStudent(StudentService studentService){
        studentService.show("张三",22);
    }

    public static void goOrder(OrderService orderService){
        orderService.show("李四");
    }
    
}

7. Prerequisites for using Lambda expressions

The syntax of Lambda expression is very concise, but Lambda expression is not used casually, there are several conditions to pay special attention to when using it

  1. The parameter or local variable type of the method must be an interface to use Lambda
  2. There is one and only one abstract method in the interface (@FunctionalInterface)

8. Comparison of Lambda and Anonymous Inner Class

Comparison of Lambda and anonymous inner class

The required type is not the same

  • The type of anonymous inner class can be class, abstract class, interface
  • The type required by the lambda expression must be an interface

The number of abstract methods is not the same

  • The number of abstract methods in the interface required by the anonymous inner class is arbitrary
  • There can be only one abstract method in the interface required by the lambda expression

The realization principle is different

  • An anonymous inner class forms a class after compilation
  • Lambda expressions dynamically generate classes when the program is running

~Okay, the content of Lambda expression is introduced here, if it is helpful to you, please like it, follow and add to favorites. V_V