パフォーマンスよりも簡潔にするために、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
を使用することです。
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