In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-18 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >
Share
Shulou(Shulou.com)06/01 Report--
This article focuses on "how to write Lambda expressions with Scala and Java8". Interested friends may wish to take a look. The method introduced in this paper is simple, fast and practical. Let's let the editor take you to learn how to write Lambda expressions by Scala and Java8.
The way Java is written-
1List names = Arrays.asList ("1", "2", "3")
2Stream lengths = names.stream () .map (name-> name.length ())
The way Scala is written-
1.val names = List ("1", "2", "3")
2.val lengths = names.map (name = > name.length)
It looks very simple on the surface, so what's wrong with the complexity behind it?
Analyze the implementation of Scala together.
The Code
I use javap (a tool that comes with jdk) to see the bytecode content contained in the class class compiled by the Scala compiler. Let's take a look at the final bytecode (this is what JVM will actually execute)
1.Compact / load the names object reference and push it into the operation stack (JVM treats it as a variable # 2)
2.Compact / it will stay for a while until called by the map function.
3.aload_2
The next thing becomes more interesting, and an instance of a composite class generated by the compiler is created and initialized. From a JVM point of view, it is through this object that the Lambda method is held. Interestingly, although Lambda is defined as a part of our method, it actually exists completely outside of our class.
New myLambdas/Lambda1 $$anonfun$1 / / new a lambda instance variable.
Dup / / pushes the lambda instance variable reference into the operation stack.
/ / finally, call its constructor. Remember, for JVM, it's just a normal object.
Invokespecial myLambdas/Lambda1 $$anonfun$1/ () V
/ / the code for these two governors loads the immutable.List CanBuildFrom factory used to create the list.
/ / this factory pattern is part of the Scala collection architecture.
Getstatic scala/collection/immutable/List$/MODULE$
Lscala/collection/immutable/List$
Invokevirtual scala/collection/immutable/List$/canBuildFrom ()
Lscala/collection/generic/CanBuildFrom
/ / now we have Lambda objects and factories in our operation stack
/ / the next step is to call the map function.
/ / if you remember, we initially pushed the names object reference to the top of the operation stack.
/ / the names object is now used as an instance of the map method call
/ / it can also accept Lambda objects and factories to generate a new collection that contains the length of the string.
Invokevirtual scala/collection/immutable/List/map (Lscala/Function1
Lscala/collection/generic/CanBuildFrom;) Ljava/lang/Object
But wait, what's going on inside the Lambda object?
Lambda object
The Lambda class is derived from scala.runtime.AbstractFunction1. The overwritten apply method can be called polymorphically by calling the map function. The code of the rewritten apply method is as follows:
Aload_0 / / load the this object reference to the operation stack
Aload_1 / / load string parameters to the operation stack
Checkcast java/lang/String / / check whether it is a string type
/ / call the apply method overridden in the composite class
Invokevirtual myLambdas/Lambda1 $$anonfun$1/apply (Ljava/lang/String;) I
/ / return value of packaging
Invokestatic scala/runtime/BoxesRunTime/boxToInteger (I) Ljava/lang/Integer
Areturn
The code that is actually used to perform the length () operation is nested in an additional apply method to simply return the length of the string we expect.
After a long walk ahead of us, we finally reached this side:
Aload_1
Invokevirtual java/lang/String/length () I
Ireturn
For the simple code we wrote above, we ended up generating a lot of bytecode, an extra class, and a bunch of new methods. Of course, this does not mean that we will give up using Lambda (we are writing scala, not C). This only shows the complexity behind these structures. Imagine that the code and complexity of Lambda expressions will be compiled into a complex chain of execution.
I expect Java8 to implement Lambda in the same way, but surprisingly, they use a completely different approach.
Java 8-A new way to implement
In the implementation of Java8, the bytecode is relatively short, but what you do is unexpected. It simply loads the names variable and calls its stream method, but what it does next is elegant. It uses a new instruction invokeDynamic added by Java7 to dynamically connect the real call point of the lambda function instead of creating an object that wraps the lambda function.
Aload_1 / / loads the names object reference and pushes it into the operation stack
/ / call its stream () method
Invokeinterface java/util/List.stream: () Ljava/util/stream/Stream
/ / Magic invokeDynamic instruction!
Invokedynamic # 0:apply: () Ljava/util/function/Function
/ / call the map method
Invokeinterface java/util/stream/Stream.map:
(Ljava/util/function/Function;) Ljava/util/stream/Stream
Magical InvokeDynamic instruction. This is a new directive in JAVA 7, which makes JVM less restrictive and allows dynamic language runtime binding symbols.
Dynamic link. If you look at the invokedynamic directive, you will find that there is actually no reference to the Lambda function (named lambda$0) because of the way invokedynamic is designed, simply the name and signature of the lambda, as in our example-
/ / A method called Lamda$0, which takes a string parameter and returns an Integer object
Lambdas/Lambda1.lambda$0: (Ljava/lang/String;) Ljava/lang/Integer
They are saved in an entry in a separate table in the .class file, and the # 0 parameter is passed to the instruction pointer when invokedynamic is executed. This new table does change the structure of the bytecode specification for the first time many years later, which requires us to adapt Takipi's error analysis engine to match it.
The Lambda code
The following bytecode is a real lambda expression. Then simply load the string parameters, call the length method to get the length, and wrap the return value. Note that it is compiled as a static method, thus avoiding passing an additional this object to him, as we saw earlier in Scala.
Aload_0
Invokevirtual java/lang/String.length: ()
Invokestatic java/lang/Integer.valueOf: (I) Ljava/lang/Integer
Areturn
Another advantage of the invokedynamic approach is that it allows us to call this method polymorphically using map functions without instantiating an encapsulated object or calling an overridden method. Very cool!
At this point, I believe you have a deeper understanding of "how to write Lambda expressions with Scala and Java8". You might as well do it in practice. Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.