如果您追求簡潔而非性能,自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);
}
但是,如果你想在標準功能接口,不允許checked異常的情況下使用它們,異常處理將主導源代碼。
可以即使在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,這是在運行時lambda表達式和方法引用的後端導入的LambdaMetafactory
。
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);
這具有較高創作的複雜性,但由於沒有技術差異不再職能的後續執行會對編譯時方法引用比肩的效率。
這是一個非常罕見的情況 - Java8語法糖爲此進行了優化的可能性很小。如果這在你的代碼庫中很常見,你可以將它移動到一個輔助方法中,然後執行'() - > Utils.invoke(obj,methodName)'。 –
@OliverCharlesworth建議做什麼是唯一的方法,這可能是一個答案 – Andremoniy
@Andremoniy不僅。還有運行時代碼。 – talex