当前位置:网站首页>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
边栏推荐
- Websites that it people often visit
- What is 5g industrial wireless gateway? What functions can 5g industrial wireless gateway achieve?
- Target free or target specific: a simple and effective zero sample position detection comparative learning method
- XSS prevention
- Pytoch --- use pytoch to predict birds
- okcc为什么云呼叫中心比传统呼叫中心更好?
- go 包的使用
- PIP installation of third-party libraries
- 初识P4语言
- How much can a job hopping increase? Today, I saw the ceiling of job hopping.
猜你喜欢
Yyds dry inventory compiler and compiler tools
Three years of experience in Android development interview (I regret that I didn't get n+1, Android bottom development tutorial
Microsoft Research Institute's new book "Fundamentals of data science", 479 Pages pdf
Target free or target specific: a simple and effective zero sample position detection comparative learning method
[untitled]
Pandora IOT development board learning (RT thread) - Experiment 1 LED flashing experiment (learning notes)
Fluent icon demo
Analysis of the overall design principle of Nacos configuration center (persistence, clustering, information synchronization)
【c语言】动态规划---入门到起立
WiFi 5GHz frequency
随机推荐
Pytorch---使用Pytorch进行图像定位
uni-app - 实现获取手机验证码倒计时 60 秒(手机号+验证码登录功能)
Go variables and constants
Federal learning: dividing non IID samples according to Dirichlet distribution
okcc为什么云呼叫中心比传统呼叫中心更好?
Li Kou interview question 02.08 Loop detection
云服务器的安全设置常识
go 函数
66.qt quick-qml自定义日历组件(支持竖屏和横屏)
IDEA xml中sql没提示,且方言设置没用。
树莓派GPIO引脚控制红绿灯与轰鸣器
Pytoch yolov5 runs bug solution from 0:
Pytorch---使用Pytorch进行鸟类的预测
Homework of the 16th week
Three ways for programmers to learn PHP easily and put chaos out of order
Delete the code you wrote? Sentenced to 10 months!
Microsoft Research Institute's new book "Fundamentals of data science", 479 Pages pdf
Recently, the weather has been extremely hot, so collect the weather data of Beijing, Shanghai, Guangzhou and Shenzhen last year, and make a visual map
Yolov5网络修改教程(将backbone修改为EfficientNet、MobileNet3、RegNet等)
5g era is coming in an all-round way, talking about the past and present life of mobile communication