问题
I've been using a lot of method references and lambdas recently, and wanted to know at runtime if i could print to screen the source of the lambda ie its name, simply for debugging reasons. I figured it might be possible using reflection, by calling getClass() within getName(), but I couldn't find a method with which to find the original source reference's name.
I have a functional interface such as:
@FunctionalInterface
public interface FooInterface {
// function etc etc irrelevant
public void method();
public default String getName() {
// returns the name of the method reference which this is used to define
}
}
then lets say i wish to test run the interface, and print the source of the functional interface to the screen.
public static void doStuff(FooInterface f) {
// prints the lambda name that is used to create f
System.out.println(f.getName());
// runs the method itself
f.method();
}
So that if i do this:
doStuff(Foo::aMethodReference);
it should print something like: "aMethodReference" to the screen, that way i can know, at runtime which methods are being run, in what order etc.
I'm quite doubtful that this is possible, considering that lambdas are not-quite-objects, but hey, i figured there could be a workaround. Furthermore, the eclipse debug tool just says its a lambda, without any other information, do lambda's retain any of this information? or is it all lost at Runtime?
Cheers. (I'm using JDK 11 if that makes any difference)
回答1:
As you're saying that you only need this for debugging purposes, here is a trick (i.e. a dirty hack) that will allow you to do what you want.
First of all, your functional interface must be Serializable
:
@FunctionalInterface
public interface FooInterface extends Serializable {
void method();
}
Now, you can use this undocumented, internal-implementation-dependent and extremely risky code to print some information about the method reference targeted to your FooInterface
functional interface:
@FunctionalInterface
public interface FooInterface extends Serializable {
void method();
default String getName() {
try {
Method writeReplace = this.getClass().getDeclaredMethod("writeReplace");
writeReplace.setAccessible(true);
SerializedLambda sl = (SerializedLambda) writeReplace.invoke(this);
return sl.getImplClass() + "::" + sl.getImplMethodName();
} catch (Exception e) {
return null;
}
}
}
When you call this method:
doStuff(Foo::aMethodReference);
You'll see the following output:
package/to/the/class/Foo::aMethodReference
Note 1: I've seen this approach in this article by Peter Lawrey.
Note 2: I've tested this with openjdk version "11" 2018-09-25
and also with java version "1.8.0_192"
.
来源:https://stackoverflow.com/questions/53387629/is-it-possible-how-to-get-the-name-of-a-method-reference-at-runtime-java