2016-05-27 7 views
0

メソッドハンドルツリーのプレースホルダにバインドされる値を引数として渡すことができるメソッドハンドルを作成したいとします。Javaメソッドハンドル:関数間でバインドされていない引数を伝播する

図、このような何か:xが呼び出しに渡されf(x) = plus(minus(x, 2), 3)、及び2と3は私が理解していない問題に実行している2または3

常に返すいくつかの定数MethodHandlesです:、私は理解していない何

Exception in thread "main" java.lang.IllegalArgumentException: target and filter types do not match: (double)double, (MethodHandle,double)double 
    at java.lang.invoke.MethodHandleStatics.newIllegalArgumentException(MethodHandleStatics.java:145) 
    at java.lang.invoke.MethodHandles.filterArgumentChecks(MethodHandles.java:2631) 
    at java.lang.invoke.MethodHandles.filterArgument(MethodHandles.java:2608) 
    at java.lang.invoke.MethodHandles.filterArguments(MethodHandles.java:2601) 
    at TTest.main(TTest.java:31) 

私が作曲プラスマイナスで、wができる方法である。

import java.lang.invoke.MethodHandle; 
import java.lang.invoke.MethodHandles; 
import java.lang.invoke.MethodType; 

public class TTest { 

    public static double plus(double a, double b) { return a + b; } 
    public static double minus(double a, double b) { return a - b; } 

    public static void main(String[] args) throws Throwable { 


     MethodHandle mh_minus = MethodHandles.lookup().findStatic(TTest.class, "minus", MethodType.methodType(double.class, double.class, double.class)); 
     MethodHandle mh_plus = MethodHandles.lookup().findStatic(TTest.class, "plus", MethodType.methodType(double.class, double.class, double.class)); 


     // f(x) = plus(minus(x, 2), 3) 
     MethodHandle doubleInvoker = MethodHandles.exactInvoker(MethodType.methodType(double.class)); 

     // mh_minus takes 2 doubles as input. The second one needs to take a MethodHandle that returns a constant: 
     MethodHandle minus_2 = MethodHandles.filterArguments(mh_minus, 1, doubleInvoker); 
     minus_2 = MethodHandles.insertArguments(minus_2, 1, MethodHandles.constant(double.class, 2)); 

     // mh_plus takes 2 doubles as input. The second one needs to take a MethodHandle that returns a constant: 
     MethodHandle plus_3 = MethodHandles.filterArguments(mh_plus, 1, doubleInvoker); 
     plus_3 = MethodHandles.insertArguments(plus_3, 1, MethodHandles.constant(double.class, 3)); 

     // the first arg of plus_3 is minus_2, but minus_2 is a MethodHandle that takes a double and returns a double, so we need to filter the first arg of plus_3 by an exact invoker 

     // EXCEPTION HERE: 
     plus_3 = MethodHandles.filterArguments(plus_3, 0, MethodHandles.exactInvoker(MethodType.methodType(double.class, double.class))); 
     MethodHandle comp = plus_3.bindTo(minus_2); 
     double res = (double)comp.invokeExact(3.0); // performs (3 - 2) + 3 
    } 
} 

これはplus_3をフィルタ処理しようとしたときに例外を返しますここではマイナスにはまだフルフィルされていない1つの引数があります。

私を助けることができますか?

答えて

0

興味のある人は、MethodHandles::collectArgumentsです。

コードは次のようになります。

public static void withCollectArguments() throws Throwable { 

     MethodHandle mh_minus  = MethodHandles.lookup().findStatic(
       TTest.class, 
       "minus", 
       MethodType.methodType(
         double.class, // output 
         double.class, // arg1 
         double.class // arg2 
       ) 
     ); 

     MethodHandle mh_plus  = MethodHandles.lookup().findStatic(
       TTest.class, 
       "plus", 
       MethodType.methodType(
         double.class, 
         double.class, 
         double.class 
       ) 
     ); 

     // this guys here is used in filters to do a MethodHandle.invoke() -> double conversion 
     MethodHandle doubleInvoker = MethodHandles.exactInvoker(
       MethodType.methodType(
         double.class 
       ) 
     ); 

     // I want: f(x) = plus(minus(x, 2.0), 3.0) === (x - 2.0) + 3.0 

     // mh_minus takes 2 doubles as input. The second one needs to 
     // take a MethodHandle that returns a constant, so we filter 
     MethodHandle x_minus_2 = MethodHandles.filterArguments(
       mh_minus, 
       1, 
       doubleInvoker 
     ); 

     x_minus_2 = MethodHandles.insertArguments(
       x_minus_2, 
       1, 
       MethodHandles.constant(double.class, 2) 
     ); 

     // this here is the magic: we collect arguments of mh_plus (double, double), 
     // starting at argument index 0,and the collector is minus_2 (double) : 
     // we will "eat" the first arg of mh_plus and replace it with minus_2 
     MethodHandle x_minus_2_plus_y = MethodHandles.collectArguments(
       mh_plus, 
       0, 
       x_minus_2 
     ); 

     // we then curry x_minus_2_plus_y with a constant as 2nd argument: y => 3 
     MethodHandle x_minus_2_plus_3 = MethodHandles.filterArguments(
       x_minus_2_plus_y, 
       1, 
       doubleInvoker 
     ); 

     // "(x - 2) + y" becomes "(x - 2) + 3" 
     x_minus_2_plus_3 = MethodHandles.insertArguments(
       x_minus_2_plus_3, 
       1, 
       MethodHandles.constant(
         double.class, 
         3 
       ) 
     ); 

     // we now have a method handle that takes 1 argument and dispatches it to minus 
     double res = (double)x_minus_2_plus_3.invokeExact(1.0); // performs (x=1.0 - 2.0) + 3.0 
     Assert.assertEquals(res, 2.0); 

     res = (double)x_minus_2_plus_3.invokeExact(5.0); // performs (x=5.0 -2.0) + 3.0 
     Assert.assertEquals(res, 6.0); 
    } 
関連する問題