将 LambdaMetafactory.metafactory() 用于普通非静态 getter
Use LambdaMetafactory.metafactory() for plain non-static getter
我有一个简单的 Person
class 和一个 getName()
那 returns 一个 String
:
public class Person {
public String getName() {...}
}
如何在运行时使用 LambdaMetafactory
为非静态方法 getName()
创建 lambda?
这是我到目前为止得到的结果:
public class MyMain {
public static void main(String[] args) throws Throwable {
GetterFunction getterFunction;
MethodHandles.Lookup lookup = MethodHandles.lookup();
String invokedMethodName = "getName";
MethodType invokedType = MethodType.methodType(GetterFunction.class);
MethodType methodType = MethodType.methodType(Object.class);
MethodHandle virtual = lookup.findVirtual(Person.class, "getName", MethodType.methodType(String.class));
CallSite site = LambdaMetafactory.metafactory(lookup,
invokedMethodName,
invokedType,
methodType,
virtual,
methodType);
getterFunction = (GetterFunction) site.getTarget().invokeExact();
System.out.println(getterFunction.getName(new Person("Ann")));
}
@FunctionalInterface
private interface GetterFunction {
String getName(Person person);
}
}
抛出:
java.lang.invoke.LambdaConversionException: Incorrect number of parameters for instance method invokeVirtual foo.Person.getName:()String; 0 captured parameters, 0 functional interface method parameters, 0 implementation parameters
at java.lang.invoke.AbstractValidatingLambdaMetafactory.validateMetafactoryArgs(AbstractValidatingLambdaMetafactory.java:193)
at java.lang.invoke.LambdaMetafactory.metafactory(LambdaMetafactory.java:303)
这个有效:
public class MyMain {
public static void main(String[] args) throws Throwable {
GetterFunction getterFunction;
final MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodType methodType = MethodType.methodType(String.class, Person.class);
final CallSite site = LambdaMetafactory.metafactory(lookup,
"invoke",
MethodType.methodType(GetterFunction.class),
methodType,
lookup.findVirtual(Person.class, "getName", MethodType.methodType(String.class)),
methodType);
getterFunction = (GetterFunction) site.getTarget().invokeExact();
System.out.println(getterFunction.invoke(new Person("Ann")));
}
@FunctionalInterface
interface GetterFunction {
String invoke(final Person callable);
}
}
只是扩展了 Geoffrey De Smet 的答案,以展示使用 Function 后的样子,因为需要进行一些小的调整:
public class MyMain {
public static void main(String[] args) throws Throwable {
MethodHandles.Lookup lookup = MethodHandles.lookup();
CallSite site = LambdaMetafactory.metafactory(lookup,
"apply",
MethodType.methodType(Function.class),
MethodType.methodType(Object.class, Object.class), // Function::apply signature
lookup.findVirtual(Person.class, "getName", MethodType.methodType(String.class)),
MethodType.methodType(String.class, Person.class) // Person::getName signature
);
Function<Person, String> getterFunction = (Function<Person, String>) site.getTarget().invokeExact();
System.out.println(getterFunction.apply(new Person("Ann")));
}
static class Person {
String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
}
我有一个简单的 Person
class 和一个 getName()
那 returns 一个 String
:
public class Person {
public String getName() {...}
}
如何在运行时使用 LambdaMetafactory
为非静态方法 getName()
创建 lambda?
这是我到目前为止得到的结果:
public class MyMain {
public static void main(String[] args) throws Throwable {
GetterFunction getterFunction;
MethodHandles.Lookup lookup = MethodHandles.lookup();
String invokedMethodName = "getName";
MethodType invokedType = MethodType.methodType(GetterFunction.class);
MethodType methodType = MethodType.methodType(Object.class);
MethodHandle virtual = lookup.findVirtual(Person.class, "getName", MethodType.methodType(String.class));
CallSite site = LambdaMetafactory.metafactory(lookup,
invokedMethodName,
invokedType,
methodType,
virtual,
methodType);
getterFunction = (GetterFunction) site.getTarget().invokeExact();
System.out.println(getterFunction.getName(new Person("Ann")));
}
@FunctionalInterface
private interface GetterFunction {
String getName(Person person);
}
}
抛出:
java.lang.invoke.LambdaConversionException: Incorrect number of parameters for instance method invokeVirtual foo.Person.getName:()String; 0 captured parameters, 0 functional interface method parameters, 0 implementation parameters
at java.lang.invoke.AbstractValidatingLambdaMetafactory.validateMetafactoryArgs(AbstractValidatingLambdaMetafactory.java:193)
at java.lang.invoke.LambdaMetafactory.metafactory(LambdaMetafactory.java:303)
这个有效:
public class MyMain {
public static void main(String[] args) throws Throwable {
GetterFunction getterFunction;
final MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodType methodType = MethodType.methodType(String.class, Person.class);
final CallSite site = LambdaMetafactory.metafactory(lookup,
"invoke",
MethodType.methodType(GetterFunction.class),
methodType,
lookup.findVirtual(Person.class, "getName", MethodType.methodType(String.class)),
methodType);
getterFunction = (GetterFunction) site.getTarget().invokeExact();
System.out.println(getterFunction.invoke(new Person("Ann")));
}
@FunctionalInterface
interface GetterFunction {
String invoke(final Person callable);
}
}
只是扩展了 Geoffrey De Smet 的答案,以展示使用 Function 后的样子,因为需要进行一些小的调整:
public class MyMain {
public static void main(String[] args) throws Throwable {
MethodHandles.Lookup lookup = MethodHandles.lookup();
CallSite site = LambdaMetafactory.metafactory(lookup,
"apply",
MethodType.methodType(Function.class),
MethodType.methodType(Object.class, Object.class), // Function::apply signature
lookup.findVirtual(Person.class, "getName", MethodType.methodType(String.class)),
MethodType.methodType(String.class, Person.class) // Person::getName signature
);
Function<Person, String> getterFunction = (Function<Person, String>) site.getTarget().invokeExact();
System.out.println(getterFunction.apply(new Person("Ann")));
}
static class Person {
String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
}