当前位置:网站首页>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
边栏推荐
- How much is the tuition fee of SCM training class? How long is the study time?
- Monkey test
- Wechat applet - realize the countdown of 60 seconds to obtain the mobile verification code (mobile number + verification code login function)
- pip 安装第三方库
- 千亿市场规模医疗美容行业的水究竟有多浑?
- Which product of anti-cancer insurance is better?
- Okcc why is cloud call center better than traditional call center?
- Jetpack's livedata extension mediatorlivedata
- The difference between vectorresize and reverse.
- Play with concurrency: draw a thread state transition diagram
猜你喜欢
Hands on deep learning (II) -- multi layer perceptron
Force buckle 540 A single element in an ordered array
Opencv learning example code 3.2.4 LUT
Microsoft Research Institute's new book "Fundamentals of data science", 479 Pages pdf
Lei Jun wrote a blog when he was a programmer. It's awesome
JVM knowledge points
Pytoch --- use pytoch to predict birds
What is 5g industrial wireless gateway? What functions can 5g industrial wireless gateway achieve?
Typescript practice for SAP ui5
A thorough understanding of the development of scorecards - the determination of Y (Vintage analysis, rolling rate analysis, etc.)
随机推荐
Fluent icon demo
Yyds dry goods inventory kubernetes introduction foundation pod concept and related operations
手撕——排序
Realizing deep learning framework from zero -- Introduction to neural network
向数据库中存入数组数据,代码出错怎么解决
Monkey test
Today's plan: February 15, 2022
Learn more about materialapp and common attribute parsing in fluent
How to solve the code error when storing array data into the database
Cloud service selection of enterprises: comparative analysis of SaaS, PAAS and IAAs
10 minutes to understand CMS garbage collector in JVM
Thinkphp6 limit interface access frequency
FAQ | FAQ for building applications for large screen devices
整理了一份ECS夏日省钱秘籍,这次@老用户快来领走
[source code analysis] NVIDIA hugectr, GPU version parameter server - (1)
云服务器的安全设置常识
The confusion I encountered when learning stm32
Hands on deep learning (II) -- multi layer perceptron
Pytorch---使用Pytorch进行鸟类的预测
Feature Engineering: summary of common feature transformation methods