当前位置:网站首页>Deep understanding of lambda expressions
Deep understanding of lambda expressions
2022-07-02 04:17:00 【Mingmingruyue senior】
One 、 background
Java 8 Of Lambda The expression is no longer “ New characteristics ”.
Now many people use... At work Lambda expression .
however , Do you really understand Lambda The underlying principle of expression ?
This paper gives its own understanding , Hopefully that helped .
Two 、 analysis
Here is a very simple code , Which USES Stream .
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class ListDemo {
public static void main(String[] args) {
List<DogDO> dogs = new ArrayList<>();
List<String> tom = dogs.stream().filter(dog -> dog.getName().startsWith("tom")).map(dog -> dog.getName().toLowerCase()).collect(Collectors.toList());
System.out.println(tom);
}
}
We use Jclasslib plug-in unit (《 Those who meet late IDEA plug-in unit 》 In the introduction ), Check bytecode :
You can also use it yourself javac and javap Instructions to execute on the command line .
Such as :
javac ListDemo.java
javap -p -s -c -v -l ListDemo
We can see one more inner class and BootstrapMethods
lambda$main$0
0 aload_0
1 ldc #20 <tom>
3 invokevirtual #21 <java/lang/String.startsWith : (Ljava/lang/String;)Z>
6 ireturn

amount to :
private static boolean lambda$main$0(String name){
return name.startsWith("tom");
}
lambda$main$1
0 aload_0
1 invokevirtual #19 <java/lang/String.toLowerCase : ()Ljava/lang/String;>
4 areturn

amount to
private static String lambda$main$1(String name){
return name.toLowerCase();
}
It can be seen from the above simple analysis , Essentially lambda The expression will eventually be compiled as a private static method .
main Method
0 new #2 <java/util/ArrayList>
3 dup
4 invokespecial #3 <java/util/ArrayList.<init> : ()V>
7 astore_1
8 aload_1
9 ldc #4 <jam>
11 invokeinterface #5 <java/util/List.add : (Ljava/lang/Object;)Z> count 2
16 pop
17 aload_1
18 ldc #6 <tom cat>
20 invokeinterface #5 <java/util/List.add : (Ljava/lang/Object;)Z> count 2
25 pop
26 aload_1
27 ldc #7 <tom jetty>
29 invokeinterface #5 <java/util/List.add : (Ljava/lang/Object;)Z> count 2
34 pop
35 aload_1
36 ldc #8 <gom jetty>
38 invokeinterface #5 <java/util/List.add : (Ljava/lang/Object;)Z> count 2
43 pop
44 aload_1
45 invokeinterface #9 <java/util/List.stream : ()Ljava/util/stream/Stream;> count 1
50 invokedynamic #10 <test, BootstrapMethods #0>
55 invokeinterface #11 <java/util/stream/Stream.filter : (Ljava/util/function/Predicate;)Ljava/util/stream/Stream;> count 2
60 invokedynamic #12 <apply, BootstrapMethods #1>
65 invokeinterface #13 <java/util/stream/Stream.map : (Ljava/util/function/Function;)Ljava/util/stream/Stream;> count 2
70 invokestatic #14 <java/util/stream/Collectors.toList : ()Ljava/util/stream/Collector;>
73 invokeinterface #15 <java/util/stream/Stream.collect : (Ljava/util/stream/Collector;)Ljava/lang/Object;> count 2
78 checkcast #16 <java/util/List>
81 astore_2
82 getstatic #17 <java/lang/System.out : Ljava/io/PrintStream;>
85 aload_2
86 invokevirtual #18 <java/io/PrintStream.println : (Ljava/lang/Object;)V>
89 return
adopt invokedynamic Instructions execute dynamic method calls .
Such as
50 invokedynamic #10 <test, BootstrapMethods #0>
We can directly on the plug-in , Click the command to jump to the corresponding official instruction document :
https://docs.oracle.com/javase/specs/jvms/se16/html/jvms-6.html#jvms-6.5.invokedynamic

from JVM file You can see This method is to realize dynamic call calculation , It is converted into a dynamic calculation call through a constant pool key amount symbol reference , among CallSite An instance is a target method call instance .
You can keep up in the plug-in
invokedynamic #10 In the constant pool #10 For the following :
among BootstrapMethods # 0 Corresponding 
You can see that this is right java.lang.invoke.LambdaMetafactory#metafactory Call to , The return value is java.lang.invoke.CallSite object , This object represents the actual execution of the target method call .
/** * Facilitates the creation of simple "function objects" that implement one * or more interfaces by delegation to a provided {@link MethodHandle}, * after appropriate type adaptation and partial evaluation of arguments. * Typically used as a <em>bootstrap method</em> for {@code invokedynamic} * call sites, to support the <em>lambda expression</em> and <em>method * reference expression</em> features of the Java Programming Language. * * <p>This is the standard, streamlined metafactory; additional flexibility * is provided by {@link #altMetafactory(MethodHandles.Lookup, String, MethodType, Object...)}. * A general description of the behavior of this method is provided * {@link LambdaMetafactory above}. * * <p>When the target of the {@code CallSite} returned from this method is * invoked, the resulting function objects are instances of a class which * implements the interface named by the return type of {@code invokedType}, * declares a method with the name given by {@code invokedName} and the * signature given by {@code samMethodType}. It may also override additional * methods from {@code Object}. * * @param caller Represents a lookup context with the accessibility * privileges of the caller. Specifically, the lookup context * must have * <a href="MethodHandles.Lookup.html#privacc">private access</a> * privileges. * When used with {@code invokedynamic}, this is stacked * automatically by the VM. * @param invokedName The name of the method to implement. When used with * {@code invokedynamic}, this is provided by the * {@code NameAndType} of the {@code InvokeDynamic} * structure and is stacked automatically by the VM. * @param invokedType The expected signature of the {@code CallSite}. The * parameter types represent the types of capture variables; * the return type is the interface to implement. When * used with {@code invokedynamic}, this is provided by * the {@code NameAndType} of the {@code InvokeDynamic} * structure and is stacked automatically by the VM. * In the event that the implementation method is an * instance method and this signature has any parameters, * the first parameter in the invocation signature must * correspond to the receiver. * @param samMethodType Signature and return type of method to be implemented * by the function object. * @param implMethod A direct method handle describing the implementation * method which should be called (with suitable adaptation * of argument types, return types, and with captured * arguments prepended to the invocation arguments) at * invocation time. * @param instantiatedMethodType The signature and return type that should * be enforced dynamically at invocation time. * This may be the same as {@code samMethodType}, * or may be a specialization of it. * @return a CallSite whose target can be used to perform capture, generating * instances of the interface named by {@code invokedType} * @throws LambdaConversionException If any of the linkage invariants * described {@link LambdaMetafactory above} * are violated, or the lookup context * does not have private access privileges. */
public static CallSite metafactory(MethodHandles.Lookup caller,
String invokedName,
MethodType invokedType,
MethodType samMethodType,
MethodHandle implMethod,
MethodType instantiatedMethodType)
throws LambdaConversionException {
AbstractValidatingLambdaMetafactory mf;
mf = new InnerClassLambdaMetafactory(caller, invokedType,
invokedName, samMethodType,
implMethod, instantiatedMethodType,
false, EMPTY_CLASS_ARRAY, EMPTY_MT_ARRAY);
mf.validateMetafactoryArgs();
return mf.buildCallSite();
}
namely lambda Expressions write code to private static methods , Then construct the implementation of the target type .
In order to see the effect more intuitively , You can IDEA Add... To this type of operating parameters
-Djdk.internal.lambda.dumpProxyClasses= The path you want to output to on your computer

You can see the compiled inner class :
have access to Luyten decompiler .
The download address is here :
View source code :

You can see that the compiler automatically generates for us Predicate and Function Inner class , Class called [ The goal is Class$$Lambda$ Numbers ] In the form of , Invoke the static method above in the internal class .
The logical level is equivalent to the following code :
package other.list;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
public class ListDemo {
public static void main(String[] args) {
List<String> dogNames = new ArrayList<>();
dogNames.add("jam");
dogNames.add("tom cat");
dogNames.add("tom jetty");
dogNames.add("gom jetty");
List<String> tom = dogNames.stream().filter(new ListDemo$$Lambda$1()).map(new ListDemo$$Lambda$2()).collect(Collectors.toList());
System.out.println(tom);
}
private static boolean lambda$min$0(String name) {
return name.startsWith("tom");
}
private static String lambda$main$1(String name) {
return name.toLowerCase();
}
static class ListDemo$$Lambda$1 implements Predicate<String> {
@Override
public boolean test(String name) {
return lambda$min$0(name);
}
}
static class ListDemo$$Lambda$2 implements Function<String, String> {
@Override
public String apply(String name) {
return lambda$main$1(name);
}
}
}
3、 ... and 、 expand
With the above explanation , I'm sure you're right Lambda Expressions have a deeper understanding .
Please guess and verify Map.forEach What is the underlying implementation of the writing method ?
Example :
import java.util.HashMap;
import java.util.Map;
public class LambdaMapDemo {
public static void main(String[] args) {
Map<Integer, String> map = new HashMap<>();
for (int i = 0; i < 10; i++) {
map.put(i, String.valueOf(i));
}
// How does the underlying layer achieve ?
map.forEach((k, v) -> {
System.out.println("k:" + k + " -> v:" + v);
});
}
}
I believe you can see below main Bytecode of function , It should already be possible to figure out how to implement it :
0 new #2 <java/util/HashMap>
3 dup
4 invokespecial #3 <java/util/HashMap.<init> : ()V>
7 astore_1
8 iconst_0
9 istore_2
10 iload_2
11 bipush 10
13 if_icmpge 37 (+24)
16 aload_1
17 iload_2
18 invokestatic #4 <java/lang/Integer.valueOf : (I)Ljava/lang/Integer;>
21 iload_2
22 invokestatic #5 <java/lang/String.valueOf : (I)Ljava/lang/String;>
25 invokeinterface #6 <java/util/Map.put : (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;> count 3
30 pop
31 iinc 2 by 1
34 goto 10 (-24)
37 aload_1
38 invokedynamic #7 <accept, BootstrapMethods #0>
43 invokeinterface #8 <java/util/Map.forEach : (Ljava/util/function/BiConsumer;)V> count 2
48 return
Please write your own logical equivalent code .
I hope you can see Lambda expression , You can make up for the ability of the underlying implementation by yourself .
Four 、 summary
A lot of knowledge seems to be used to it , But you can continue to dig deep , You can learn different knowledge .
Only when we really understand a knowledge point can we have enough confidence in the interview .
in addition Lambda Is good , But don't “ Covetous cup ”, The abuse of Lambda There will be challenges to the readability and maintainability of the code .
If you are interested, you can continue to read another article :
《Lambda The solution to the complexity brought by expressions 》
It's not easy to create , If this article helps you , Welcome to thumb up 、 Collection and attention , Your support and encouragement , It's the biggest driving force of my creation .
Reprint please indicate the source :https://blog.csdn.net/w605283073/article/details/121571573
边栏推荐
- Delete the code you wrote? Sentenced to 10 months!
- Force buckle 540 A single element in an ordered array
- Go function
- 【leetcode】34. Find the first and last positions of elements in a sorted array
- How much can a job hopping increase? Today, I saw the ceiling of job hopping.
- Installation et utilisation du lac bleu
- Www2022 | know your way back: self training method of graph neural network under distribution and migration
- Jetpack's livedata extension mediatorlivedata
- Wechat applet - realize the countdown of 60 seconds to obtain the mobile verification code (mobile number + verification code login function)
- Nacos 配置中心整体设计原理分析(持久化,集群,信息同步)
猜你喜欢

【leetcode】74. Search 2D matrix

文档声明与字符编码

Use a mask to restrict the input of the qlineedit control
![[source code analysis] NVIDIA hugectr, GPU version parameter server - (1)](/img/e1/620443dbc6ea8b326e1242f25d6d74.jpg)
[source code analysis] NVIDIA hugectr, GPU version parameter server - (1)

Microsoft Research Institute's new book "Fundamentals of data science", 479 Pages pdf

藍湖的安裝及使用

The first practical project of software tester: web side (video tutorial + document + use case library)

Pytoch --- use pytoch for image positioning

Yolov5 network modification tutorial (modify the backbone to efficientnet, mobilenet3, regnet, etc.)

【c语言】动态规划---入门到起立
随机推荐
The first practical project of software tester: web side (video tutorial + document + use case library)
[untitled]
《动手学深度学习》(二)-- 多层感知机
Is it safe to open an account with first venture securities? I like to open an account. How can I open it?
Yyds dry inventory compiler and compiler tools
[untitled]
The difference between vectorresize and reverse.
Force buckle 540 A single element in an ordered array
Today's plan: February 15, 2022
Yolov5 network modification tutorial (modify the backbone to efficientnet, mobilenet3, regnet, etc.)
60后关机程序
Installation et utilisation du lac bleu
Wechat applet map annotation
Learn more about materialapp and common attribute parsing in fluent
office_ Delete the last page of word (the seemingly blank page)
MySQL advanced SQL statement 2
Is the product of cancer prevention medical insurance safe?
Www 2022 | rethinking the knowledge map completion of graph convolution network
Nacos 配置中心整体设计原理分析(持久化,集群,信息同步)
cookie、session、tooken
