How to get method parameter names in jamba java 8 expression?

from How to get method parameter names in Java 8 using reflection? I know that using the javac -parameters argument can contain parameter names in a * .class file. but is this not valid in lambda expression?

Example:

 import java.lang.reflect.Method; import java.lang.reflect.Parameter; public class MyTest { public static void main(String[] args) { for(Method m : Test.class.getDeclaredMethods()) { System.out.println(m.getName()); for(Parameter p : m.getParameters()) { System.out.println(" => " + p.getName()); } } } } interface MyInterface { Object doSomething(int a, int b); } class Test { private void bar(MyInterface iface) { } public void foo() { bar((x, y) -> null); } } 

When i do

 javac -parameters MyTest.java java MyTest 

He is typing

 bar => iface foo lambda$foo$0 => arg0 => arg1 

I am trying to do javap -c -p -verbose Test :

 { Test(); descriptor: ()V flags: Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 21: 0 private void bar(MyInterface); descriptor: (LMyInterface;)V flags: ACC_PRIVATE Code: stack=0, locals=2, args_size=2 0: return LineNumberTable: line 24: 0 MethodParameters: Name Flags iface public void foo(); descriptor: ()V flags: ACC_PUBLIC Code: stack=2, locals=1, args_size=1 0: aload_0 1: invokedynamic #2, 0 // InvokeDynamic #0:doSomething:()LMyInterface; 6: invokespecial #3 // Method bar:(LMyInterface;)V 9: return LineNumberTable: line 27: 0 line 28: 9 private static java.lang.Object lambda$foo$0(int, int); descriptor: (II)Ljava/lang/Object; flags: ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC Code: stack=1, locals=2, args_size=2 0: aconst_null 1: areturn LineNumberTable: line 27: 0 } 

I can find the name of the iface parameter, but I cannot find x or y

+5
source share
1 answer

This does not seem to be a problem for the lambda expressions themselves:

 interface MyInterface { void doSomething(int a, int b); } class Test { private void bar(MyInterface iface) { iface.doSomething(0, 0); } public void foo() { bar((x, y) -> System.out.println(x)); } } 

Uses a single lambda expression to make it simple. After compiling with the -parameters option -parameters we can use javap -c -p -verbose Test to find out more:

 private static void lambda$foo$0(int, int); descriptor: (II)V flags: ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC Code: stack=2, locals=2, args_size=2 0: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream; 3: iload_0 4: invokevirtual #6 // Method java/io/PrintStream.println:(I)V 7: return LineNumberTable: line 15: 0 MethodParameters: Name Flags x synthetic y synthetic 

Parameter names ( x and y ) are! Iterate over such methods

 for(Method m : Test.class.getDeclaredMethods()) { System.out.println(m.getName()); for(Parameter p : m.getParameters()) { System.out.println(" => " + p.getName()); } } 

displays parameter names correctly:

 lambda$foo$0 => x => y 

Instead of being a problem with lamps, it's actually just hard to determine the right method. If you try to get the parameter names using getDeclaredMethods() on the interface instance passed to this method (like @Didier L suggested in the comment), you will have problems. For example, using

 iface.getClass().getDeclaredMethods() 

in bar() will not work as you might expect. If you get a class name, for example. for example iface.getClass().getName() , you will see something like this:

 Test$$Lambda$1/834600351 

This is a dynamically created class, you can argue about whether it exists at all. Since it is not generated by the compiler, it does not provide any information about local variables or their names, because the method implemented by the interface simply does not match your lambda . This is an important difference.

This "virtual class" provides a method, for example. doSomething(int, int) to implement this interface ( MyInterface ), but this public method is different from the method you create to define lambda ( lambda$foo$0 ).

Therefore, the doSomething method of the generated "virtual class" does not carry parameter information. A dynamically created class hides your implementation.


Your second example does not suffer from this problem:

 map("bibi", new A() { @Override public JSONObject exec(String u, String s, String b) { return null; } }); 

You explicitly define a class that implements the A interface, and you explicitly provide the exec method, so all information is present.

+4
source

Source: https://habr.com/ru/post/1240066/


All Articles