Early experience

What is a lambda expression? No ink, directly on the most classic threads for the first experience

When lambda expressions are not used, we create the way threads are written

package com.features.lambda.demo01;
// Take a look at lambda expressions through threads
public class demo01 {
    public static void main(String[] args) {
        //
        new Thread(new Runnable() {
            @Override
            public void run(a) {
                System.out.println("New thread created:"+Thread.currentThread().getName()); } }).start(); }}Copy the code

Code analysis and problem finding

  1. The Thread class takes a Runnable interface as a parameter. 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. We have to override the abstract run method. All the method names, method parameters, and method return values have to be rewritten without error, but we only care about the code inside the run method
  • Lambda therefore arises from this problem

First taste of lambda expressions — Creating a new thread

package com.features.lambda.demo01;
// Take a look at lambda expressions through threads
public class demo01 {
    public static void main(String[] args) {
        / / lambda method
        new Thread(()->{
            System.out.println("New thread created:"+Thread.currentThread().getName()); }).start(); }}Copy the code
  • You can find
  1. A lambda expression is an anonymous function that can be understood as a piece of code that can be passed
  2. Lambda expressions simplify the use of anonymous inner classes with simpler syntax.
  3. Lambda expressions make code much more concise

Lambda expression syntax

Lambda expression composition

Lambda expressions consist of three parts: () -> {}

(Parameter list) -> {method body code}Copy the code
  • (a)Fill in the parameters in
  • ->Fixed notation, split argument list and method body code
  • {}To write the code for our method body

Conditions for the use of lambda expressions

  1. The parameter or local variable type of a method must be an interface
  2. In the interfaceThere is and only one abstract method(@FunctionalInterface)

@ FunctionalInterface annotations

  1. An informational annotation type used to indicate that an interface type declaration is a functional interface defined by the Java language specification. Conceptually, a functional interface has only one abstract method. Because default methods have an implementation, they are not abstract. If the interface declares an abstract method, that method overrides a public method of java.lang. Object, which also does not count toward the abstract method count of the interface, because any implementation of the interface will have an implementation from java.lang.Object or elsewhere.

  2. Note that instances of function interfaces can be created using lambda expressions, method references, or constructor references.

  3. If a type is annotated with this annotation type, the compiler needs to generate an error message unless:

    • This type is an interface type, not an annotation type, enumeration, or class.
    • Annotated types meet the requirements of functional interfaces.
  4. However, the compiler will treat any interface that satisfies the FunctionalInterface definition as a function interface, regardless of whether FunctionalInterface annotations exist in the interface declaration.

In summary, the @functionalInterface annotation is used to ensure that the interface allows only one abstract method to be defined

Abbreviation for 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

Just like when you’re creating a thread

new Thread(
    () -> System.out.println("New thread created:"+Thread.currentThread().getName())
).start();
Copy the code

Lambda vs 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
  1. The number of abstract methods is not the same
  • 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
  1. The implementation principle is not the same
  • Anonymous inner classes are compiled to form a class
  • Lambda expressions generate classes dynamically at runtime

Lambda principle analysis

Let’s take creating a thread as an example

Methods a

package com.features.lambda.demo01;
// Take a look at lambda expressions through threads
public class demo01 {
    public static void main(String[] args) {
         new Thread(new Runnable() {
             @Override
             public void run(a) {
                 System.out.println("New thread created:"+Thread.currentThread().getName()); } }).start(); }}Copy the code

Way 2

package com.features.lambda.demo01;
// Take a look at lambda expressions through threads
public class demo01 {
    public static void main(String[] args) {
        new Thread(()->{
            System.out.println("New thread created:"+Thread.currentThread().getName()); }).start(); }}Copy the code

Class file is generated by the anonymous inner class, demo01$1. Class file is the essence of the anonymous inner class implementation; This means that lambda expressions do not generate anonymous inner class class files. That is, Java8 does not rely on the compiler to convert lambda to anonymous inner classes

At this point, we decomcompile Demo01.class using javap, a tool that comes with the JDK (note that you need to find the demo01.class file location and run the command there)

Enter the command to decompile

Javap -c -p File name. Class -c decompiles the code (-c can also be replaced with -v, for more details) -p displays all classes and membersCopy the code

Result of decompilation:

D:\Users\ASUS\JDK8-new-features\target\classes\com\features\lambda\demo01>javap -c -p demo01.class Compiled from "demo01.java" public class com.features.lambda.demo01.demo01 { public com.features.lambda.demo01.demo01(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: new #2 // class java/lang/Thread 3: dup 4: invokedynamic #3, 0 // InvokeDynamic #0:run:()Ljava/lang/Runnable; 9: invokespecial #4 // Method java/lang/Thread."<init>":(Ljava/lang/Runnable;) V 12: invokevirtual #5 // Method java/lang/Thread.start:()V 15: return private static void lambda$main$0(); Code: 0: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream; 3: new #7 // class java/lang/StringBuilder 6: dup 7: Invokespecial #8 // Method Java /lang/StringBuilder."<init>":()V 10: LDC #9 invokevirtual #10 // Method java/lang/StringBuilder.append:(Ljava/lang/String;) Ljava/lang/StringBuilder; 15: invokestatic #11 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread; 18: invokevirtual #12 // Method java/lang/Thread.getName:()Ljava/lang/String; 21: invokevirtual #10 // Method java/lang/StringBuilder.append:(Ljava/lang/String;) Ljava/lang/StringBuilder; 24: invokevirtual #13 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 27: invokevirtual #14 // Method java/io/PrintStream.println:(Ljava/lang/String;) V 30: return }Copy the code

In the result of the decompilation, we see that it creates a private static void lambda$main$0(); Method, in fact, this should be the lambda expression corresponding to the method, we can use the debug method to test

Lambda $main$0() static method is as follows

 private static void lambda$main$0(){
     System.out.println("New thread created:"+Thread.currentThread().getName());
 }
 
Copy the code

In order to more intuitive understanding of the it, we can add Java at run time – Djdk. Internallambda. DumpProxyClasses to run the package name. The class name command, along with this argument, prints the internal class code to a file (note that the command is run from classes).

D:\Users\ASUS\JDK8-new-features\target\classes>java -Djdk.internallambda.dumpProxyClasses com.features.lambda.demo01.demo01
Copy the code

Results:

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 body is the code in the Lambda expression, i.eprivate static void lambda$main$0()methods
  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