我正在尝试使用变量创建方法引用,该变量保存来自对象的某些方法的方法名称:
SomeClass obj = new SomeClass();
String methodName = "someMethod";
我正在寻找精确创建obj::someMethod
的方法,但为此使用变量methodName。有可能吗?
我知道如何从methodName
和obj
创建功能界面实例:
() -> {
try {
return obj.getClass().getMethod(methodName).invoke(obj);
} catch (NoSuchMethodException | IllegalAccessException e) {
return null;
}
};
但我想知道这可以用更简短的方式完成。
答案 0 :(得分:1)
这是一种非常罕见的情况 - Java8语法糖已经针对此进行了优化的可能性极小。特别是,通常的编译时类型检查不可能发生(请记住,方法引用只是遵循特定类型契约的匿名类的语法糖)。
如果这种模式在您的代码库中很常见(希望它不是!),您可以将它移动到静态实用程序方法,然后执行() -> Utils.invoke(obj, methodName)
。
答案 1 :(得分:1)
如果你力求简洁而不是表现,那么自Java 1.4以来就有Expression
和Statement
。
Object obj="example";
String methodName="substring";
Object[] arg={ 2, 5 };
try {
Object result=new Expression(obj, methodName, arg).getValue();
new Statement(System.out, "println", new Object[]{ result }).execute();
} catch (Exception ex) {
Logger.getLogger(YourClass.class.getName()).log(Level.SEVERE, null, ex);
}
但是如果你想在标准函数接口的上下文中使用它们,这些接口不允许检查异常,那么异常处理将主导源代码。
即使在Java 7下,您也可以将反射获取的方法绑定到功能接口:
Object obj="example";
String methodName="substring";
Object[] arg={ 2, 5 };
Supplier<String> s;
Consumer<String> c;
try {
MethodHandle mh=MethodHandles.insertArguments(
MethodHandles.lookup().bind(obj, methodName,
MethodType.methodType(String.class, int.class, int.class)),
0, arg);
s = MethodHandleProxies.asInterfaceInstance(Supplier.class, mh);
mh=MethodHandles.lookup().bind(System.out, "println",
MethodType.methodType(void.class, String.class));
c = MethodHandleProxies.asInterfaceInstance(Consumer.class, mh);
} catch(NoSuchMethodException | IllegalAccessException ex) {
Logger.getLogger(YourClass.class.getName()).log(Level.SEVERE, null, ex);
return;
}
String result=s.get();
c.accept(result);
这不短,但避免在每个功能评估中执行反射查找。
使用Java 8中引入的LambdaMetafactory
可能更有效率,Java 8是运行时lambda表达式和方法引用的后端。
Object obj="example";
String methodName="substring";
Object[] arg={ 2, 5 };
Supplier<String> s;
Consumer<String> c;
try {
final MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle mh=lookup.findVirtual(String.class, methodName,
MethodType.methodType(String.class, int.class, int.class));
s = (Supplier<String>)LambdaMetafactory.metafactory(lookup, "get",
mh.type().changeReturnType(Supplier.class),
MethodType.methodType(Object.class), mh, MethodType.methodType(String.class))
.getTarget().bindTo(obj).invokeWithArguments(arg);
mh=MethodHandles.lookup().findVirtual(PrintStream.class, "println",
MethodType.methodType(void.class, String.class));
c = (Consumer<String>)LambdaMetafactory.metafactory(lookup, "accept",
MethodType.methodType(Consumer.class, PrintStream.class),
MethodType.methodType(void.class, Object.class), mh,
MethodType.methodType(void.class, String.class))
.getTarget().bindTo(System.out).invokeExact();
} catch(Throwable ex) {
Logger.getLogger(YourClass.class.getName()).log(Level.SEVERE, null, ex);
return;
}
String result=s.get();
c.accept(result);
这具有更高的创建复杂性,但随后执行的函数将具有与编译时方法引用相同的效率,因为不再存在技术差异。