Reprint: http://blog.csdn.net/u012961566/article/details/78281654
To support functional programming, Java 8 introduces lambda expressions, so how do you implement lambda expressions in Java 8? After the lambda expression has been compiled, what exactly does it generate? Before we go into the analysis, let's consider that each lambda expression in Java 8 must have a functional interface corresponding to it, the difference between the functional interface and the ordinary interface, you can refer to the previous content, So you might be wondering if the lambda expression is transformed into an implementation class of the corresponding functional interface, and then the implementation of the subclass is called by polymorphic means, as the following code is a sample of a lambda expression
@FunctionalInterfaceinterface print<t> {public void Print (T x);} public class Lambda {public static void Printstring (String s, print<string> Print) { print.print (s); } Public static void Main (string[] args) { printstring ("Test", (x), System.out.println (x));} }
According to the above analysis, after the compiler has been processed in theory, the resulting code should be as follows:
@FunctionalInterfaceinterface print<t> {public void Print (T x);} Class Lambda$$0 implements print<string> { @Override public void Print (String x) { SYSTEM.OUT.PRINTLN (x); }} public class Lambda {public static void Printstring (String s, print<string> Print) { print.print (s); } public static void Main (string[] args) { printstring ("Test", New lambda$$0 ());} }
or an inner class implementation, the code looks like this:
@FunctionalInterfaceinterface print<t> {public void Print (T x);} public class Lambda { final class Lambda$$0 implements print<string> { @Override public void Print ( String x) { System.out.println (x); } } public static void Printstring (String s, print<string> Print) { print.print (s); } public static void Main (string[] args) { printstring ("Test", New Lambda (). New lambda$$0 ());} }
Or this anonymous inner class implementation, the code looks like this:
@FunctionalInterfaceinterface print<t> {public void Print (T x);} public class Lambda {public static void Printstring (String s, print<string> Print) { print.print (s); } public static void Main (string[] args) { printstring ("Test", new Print<string> () { @Override public void print (String x) { System.out.println (x); }} );} }
The code above, in addition to the code length of a point, with the implementation of the lambda expression code to run the result is the same, then how is Java 8 implemented in what way? is not one of the above three implementations, you may feel that you think is right, in fact, is right, in Java 8 is the use of internal classes to implement a lambda expression
So how is lambda expression implemented?
In order to explore how lambda expressions are implemented, it is necessary to study the bytecode files that are eventually converted into lambda tables, which requires a bytecode viewing tool and a counter-compilation tool in the Bin directory of the JDK
Javap-p Lambda.class
The-p in the above command indicates that all classes and members are output, and the result of running the above command is as follows:
Compiled from ' Lambda.java ' public class lambda {public lambda (); public static void Printstring (Java.lang.String, print<java.lang.string>); public static void Main (java.lang.string[]); private static void Lambda$0 (java.lang.String);}
As you can see from the code above, the compiler generates a private static function based on a lambda expression, noting that the build is what is said here, not the equivalent
private static void Lambda$0 (java.lang.String);
To verify that the above conversions are correct? We define a function in the code that lambda$0 this, and the final code looks like this:
@FunctionalInterfaceinterface print<t> {public void Print (T x);} public class Lambda {public static void Printstring (String s, print<string> Print) { print.print (s); } private static void Lambda$0 (String s) { } public static void Main (string[] args) { printstring ("Test", (x ), System.out.println (x));} }
The above code will not error at compile time, but the runtime will error, because there are two lambda$0 functions, as shown below, is the runtime errors
Exception in thread ' main ' Java.lang.ClassFormatError:Duplicate method Name&signature in class file Lambda at Java.lang.ClassLoader.defineClass1 (Native Method) at Java.lang.ClassLoader.defineClass (classloader.java:760) at JAV A.security.secureclassloader.defineclass (secureclassloader.java:142) at Java.net.URLClassLoader.defineClass ( urlclassloader.java:467) at java.net.urlclassloader.access$100 (urlclassloader.java:73) at java.net.URLClassLoader$ 1.run (urlclassloader.java:368) at Java.net.urlclassloader$1.run (urlclassloader.java:362) at Java.security.AccessController.doPrivileged (Native Method) at Java.net.URLClassLoader.findClass ( urlclassloader.java:361) at Java.lang.ClassLoader.loadClass (classloader.java:424) at sun.misc.launcher$ Appclassloader.loadclass (launcher.java:331) at Java.lang.ClassLoader.loadClass (classloader.java:357) at Sun.launcher.LauncherHelper.checkAndLoadMain (launcherhelper.java:495)
The above error code is deserialized by JAVAP, and the members of the output class after the decompile are as follows
Compiled from ' Lambda.java ' public class lambda {public lambda (); public static void Printstring (Java.lang.String, print<java.lang.string>); private static void Lambda$0 (java.lang.String); public static void Main (java.lang.string[]); private static void Lambda$0 (java.lang.String);}
Will find that lambda$0 appears two times, so when the code is running, it is not known which to call, so it will be thrown wrong.
With the above, it can be known that the lambda expression in Java 8 first generates a private static function, the private static function is the content of the lambda expression, so the above code can initially be converted to the code shown below
@FunctionalInterfaceinterface print<t> {public void Print (T x);} public class Lambda {public static void Printstring (String s, print<string> Print) { print.print (s); } private static void Lambda$0 (String x) { System.out.println (x); } public static void Main (string[] args) { printstring ("Test",/**lambda expression**/);} }
After the conversion to the above form, then how to implement the call static Lambda$0 function, here can be a breakpoint in the following method, you can find in the lambda expression, the runtime will enter this function
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 ();}
In this function, it can be found that an inner class was generated for the lambda expression, in order to verify that an inner class was generated, You can add-djdk.internal.lambda.dumpproxyclasses at run time, add this parameter, and the runtime will output the generated inner class code to a file
Final class lambda$ $Lambda implements Print { private lambda$ $Lambda $ (); public void print (Java.lang.Object);}
If you run Javap-c-P then the results are as follows
Final class lambda$ $Lambda implements Print { private lambda$ $Lambda $ (); Code: 0:aload_0 1:invokespecial #10 //Method java/lang/object. " <init> ":() V 4:return public void print (java.lang.Object); Code: 0:aload_1 1:checkcast #14 //class java/lang/string 4:invokestatic #20 Method lambda.lambda$0: (ljava/lang/string;) V 7:return}
By using the bytecode directive above, we can find that the implementation is called Lambda.lambda$0, which is a private static method.
So the final lambda expression is equivalent to the following form
@FunctionalInterfaceinterface print<t> {public void Print (T x);} public class Lambda {public static void Printstring (String s, print<string> Print) { print.print (s); } private static void Lambda$0 (String x) { System.out.println (x); } Final class $Lambda implements print{ @Override public void Print (Object x) { lambda$0 ((String) x); } } public static void Main (string[] args) { printstring ("Test", New Lambda (). New $Lambda $ ());} }
Java 8 Lambda Implementation principle analysis