我最近一直在使用许多方法引用和lambda,并想在运行时知道是否可以打印以筛选lambda的来源(即其名称),仅出于调试原因。我想通过在getName()中调用getClass()使用反射可能是可行的,但是我找不到找到原始源引用名称的方法。
我有一个功能界面,例如:
@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
}
}
然后可以说我希望测试运行该界面,并将功能界面的源打印到屏幕上。
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();
}
因此,如果我这样做:
doStuff(Foo::aMethodReference);
它应该在屏幕上打印类似“ aMethodReference”的内容,这样我可以在运行时知道正在运行哪些方法,以什么顺序运行等。
考虑到lambda不是完全对象,我非常怀疑这是否可行,但是,我认为可能有解决方法。此外,eclipse调试工具只是说它是lambda,没有任何其他信息,lambda是否保留这些信息中的任何信息吗?还是全部在运行时丢失了?
干杯。 (如果有任何不同,我正在使用JDK 11)
答案 0 :(得分:1)
正如您所说的,您仅需要将其用于调试目的,这是一个技巧(即肮脏的hack),可让您做自己想做的事。
首先,您的功能接口必须为Serializable
:
@FunctionalInterface
public interface FooInterface extends Serializable {
void method();
}
现在,您可以使用此未记录的,内部实现相关的且极具风险的 代码来打印有关方法参考 targeted 的一些信息。到您的FooInterface
功能界面:
@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;
}
}
}
调用此方法时:
doStuff(Foo::aMethodReference);
您将看到以下输出:
package/to/the/class/Foo::aMethodReference
注1:我在this article by Peter Lawrey中看到了这种方法。
注意2:我已经使用openjdk version "11" 2018-09-25
和java version "1.8.0_192"
对此进行了测试。