Is it possible (how) to get the name of a method reference at Runtime Java? [duplicate]

孤人 提交于 2019-12-23 19:12:53

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!