JAVA lambda expression weird tricks

lamda expression

Setting operations of traditional code space

package org.example.lambda;

public class theFirstLambda {<!-- -->
    public static void main(String[] args) {<!-- -->
        //This is the basic understanding of implementing anonymous inner class operations
        //Anonymous inner classes are generally used to implement method operations defined by the interface
        Thread thread=new Thread(new Runnable() {<!-- -->
            @Override
            public void run() {<!-- -->
                System.out.println("The thread performed the operation");
            }
        });
        thread.start();
    }
}

Using lambda operations to implement anonymous expression operations

package org.example.lambda;

public class theFirstLambda {<!-- -->
    public static void main(String[] args) {<!-- -->
        //This is the basic understanding of implementing anonymous inner class operations
        //Anonymous inner classes are generally used to implement method operations defined by the interface
        Thread thread=new Thread(()->{<!-- -->
            System.out.println("This is an anonymous expression operation understanding");
        });
        thread.start();
    }
}

  • At the bottom level, the Java virtual machine does not generate the expression file of the corresponding anonymous inner class for the lambda expression object. Overall, it does not save much space. In fact, the anonymous inner class is embedded into the main class.

  • You can use javap -v to view related bytecode file operations

    • Through an in-depth understanding of the underlying bytecode of lambda, you can completely see that the virtual machine will perform certain operations on the anonymous inner classes during execution. This is not a vague understanding at all. I It seems that I have discovered a new continent. Whether this continent can make me a great god, it should be a key to truly get to the bottom of this virtual machine! ! !

    Five ways to view bytecode in Java and IDEA_How to view file bytecode-CSDN Blog

    Bytecode file of main class

Bytecode file of anonymous inner class

  • It is obvious that the two classes are in a mutual calling relationship, but using the syntax sugar operation of lambda, let’s see what changes will happen at the bottom.

The two methods form an inline operation, and a corresponding anonymous expression class is automatically generated. This class is the underlying construction method of the anonymous expression.


  • Regarding the stack information operation understanding of 24, it is obvious that an automatically generated method has emerged, which is the corresponding overall bytecode information understanding!
Exception in thread "Thread-0" java.lang.RuntimeException: Here is the thread exception operation
at org.example.lambda.theFirstLambda.lambda$main$0(theFirstLambda.java:8)
at java.base/java.lang.Thread.run(Thread.java:834)

  • You can also find in the form of throwing exceptions that an automatic class operation understanding is implemented using Lambda operations.

Okay, having said that, let me talk about the common situations of lambda expressions. Lambda is generally used to implement the abstract method of the interface. Using lambda, you can not implement the implementation class of the interface and reduce the amount of code, but in general Generally speaking, this is a kind of syntactic sugar for Java. I think this way of writing is quite pretentious in daily operations, but the method used by lambda to implement interfaces is indeed very high-quality, reducing the space utilization of the underlying code. The rate is indeed relatively good, it depends on what readers like.

Demo of implementing a lambda expression of a custom class

package org.example.lambda.testInterface;

@FunctionalInterface
public interface theTestInterface {<!-- -->
    String backString(Integer index);
}

  • If an interface needs to implement lambda expressions, then the interface must be annotated with @FunctionalInterface so that lambda syntax can be used, otherwise the overall program will still have certain errors.
theTestInterface theTestInterface=(Integer i)-> "this is why we play:" + i;
        //Such an implementation is obviously more powerful. It directly uses reference operations to transfer the parameters of the object.
        System.out.println(theTestInterface.backString(3));

Using anonymous expressions to implement interface methods has indeed reduced the amount of code, and I think the underlying space has also been reduced.

lambda and cpp method references

Lambda expression operations are used here to provide code writers with some performance features of cpp. I am actually not familiar with cpp, but the idea reflected here is also the same. Method references in a class are used to implement the abstract methods of the interface. , is this corresponding connection relationship very high-quality? This is what this little trick taught me. It can be understood as a pointer connection operation!

 theTestInterface theTestInterface2=thelambda::backString;
        //Passing a method reference is equivalent to performing an implementation operation. The method of operating the interface here is very powerful.
        System.out.println(theTestInterface2.backString(3));
        //Other operations implemented using related operations
        thelambda thelambda=new thelambda();
        //Method reference is like pointer understanding operation
        theTestInterface theTestInterface3=thelambda::backNoStaticString;
        System.out.println(theTestInterface3.backString(9));
    }
    public static String backString(Integer i){<!-- -->
        return "this is the string:" + i;
    }
    public String backNoStaticString(Integer i){<!-- -->
        return "why we want to be:" + i;
    }
  • If it is a static method, you can directly use the main class to reference it.
  • If it is a non-static method, then the object needs to be created and then referenced.

Readers must be very familiar with this. This is actually a pointer idea. Of course, it is definitely safer in Java than in C!

As long as the above annotated class or interface is implemented

Both can use lambda expressions to operate, and can use method reference operations.

package org.example.lambda.theArrayLambda;

import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Comparator;

public class theArrayLambda {<!-- -->

    //The essence of method reference passing operation is still the understanding of pointer operation!
    public static void main(String[] args) {<!-- -->
        Integer[] integer=new Integer[] {<!-- -->8,234,32,25,6,523,1,2,2345};
        //Pay attention to the operation implementation between parameters
Arrays.sort(integer,Integer::compare)
        //You can use the return value operation to perform comparison operations, but is this method really more flexible?
        //Arrange in descending order to implement operations
        Arrays.sort(integer,theArrayLambda::smallCompare);
        System.out.println(Arrays.toString(integer));
    }
    //It's just an ascending order operation. Isn't this also the default operation understanding?
    public static int smallCompare(int x,int y){<!-- -->
        return (x>y) ? -1:((x==y)?0:1);
    }
}

  • You can use the return value for method reference
  • You can also use related custom objects for reference

Also, you must get used to ternary expressions. This expression is also a coding technique that reduces the amount of code and improves abstraction capabilities!

I am a programmer who loves life, welcome to follow my blog!