3

Method Reference for a specific method in Java 8 can be obtained as Class::Method. But how to get the method reference of all methods of a class?

All the desired methods have different method names, but the same type signature. Also, the names of the methods is not known before hand.

Example:

class Test {
    public static double op0(double a) { ... }
    public static double op1(double a) { ... }
    public static double op2(double a) { ... }
    public static double op3(double a) { ... }
    public static double op4(double a) { ... }
}

The method reference to a known method op0 can be obtained as:

DoubleFunction<Double> f = Test::op0;

But, how to get the method references of all methods in the class?

Holger
  • 285,553
  • 42
  • 434
  • 765
wolfram77
  • 2,841
  • 3
  • 23
  • 33
  • You mean how to get these in the IDE's content assist? – Konstantin Yovkov Mar 30 '15 at 13:28
  • No, to get the method references, so that they can be called at a later point of time. This is possible using `Reflection`, but i was looking for an easier alternative. – wolfram77 Mar 30 '15 at 13:32
  • Also the statement *the desired methods have different function names, but the same function signature* is wrong. The signature includes the method name and the list of parameters. The return-type is not part of the method signature. – Konstantin Yovkov Mar 30 '15 at 13:33
  • Sorry, my mistake. It should be called [Type Signature](http://en.wikipedia.org/wiki/Type_signature). – wolfram77 Mar 30 '15 at 13:35

1 Answers1

4

There is no solution that works without Reflection as the dynamic discovery of existing methods is a reflective operation. However, once methods are discovered and a method reference instance (or the dynamic equivalent of it) has been created, the actual invocation of the code runs without Reflection:

class Test {
    public static double op0(double a) { ... }
    public static double op1(double a) { ... }
    public static double op2(double a) { ... }
    public static double op3(double a) { ... }
    public static double op4(double a) { ... }

    static final Map<String, DoubleUnaryOperator> OPS;
    static {
        HashMap<String, DoubleUnaryOperator> map=new HashMap<>();
        MethodType type=MethodType.methodType(double.class, double.class);
        MethodType inT=MethodType.methodType(DoubleUnaryOperator.class);
        MethodHandles.Lookup l=MethodHandles.lookup();
        for(Method m:Test.class.getDeclaredMethods()) try {
          if(!Modifier.isStatic(m.getModifiers())) continue;
          MethodHandle mh=l.unreflect(m);
          if(!mh.type().equals(type)) continue;
          map.put(m.getName(), (DoubleUnaryOperator)LambdaMetafactory.metafactory(
            l, "applyAsDouble", inT, type, mh, type).getTarget().invokeExact());
        } catch(Throwable ex) {
            throw new ExceptionInInitializerError(ex);
        }
        OPS=Collections.unmodifiableMap(map);
    }
}

Once the class has been initialized, you can invoke a particular op without Reflection using OPS.get(name).applyAsDouble(doubleValue) or invoke all ops using, e.g.

OPS.forEach((name,op)-> System.out.println(name+'('+42+") => "+op.applyAsDouble(42)));
Holger
  • 285,553
  • 42
  • 434
  • 765
  • Thanks @Holger. I had already found your answers [here](http://stackoverflow.com/questions/19557829/faster-alternatives-to-javas-reflection) and [here](http://stackoverflow.com/questions/27602758/java-access-bean-methods-with-lambdametafactory/27605965) which solved my problem. That helps me to do the same with instance methods. It is indeed really fast. – wolfram77 Apr 08 '15 at 05:46
  • why did you use `DoubleUnaryOperator` instead of `DoubleFunction`? and how is `"applyAsDouble"` method name is enough without specifying the class or interface name? – wolfram77 Apr 08 '15 at 05:48
  • 2
    `DoubleFunction` is a function which consumes a `double` and returns an `Object`; `DoubleUnaryOperator` consumes a `double` and returns a `double`, thus perfectly matches the signature of the methods in your example. The desired `interface` is derived from the return type of the `invokedynamic` instruction; in our Reflective usage it appears twice. The `invokedType` parameter (the `inT` variable) specifies the return type and our `invokeExact()` call is *signature polymorphic* and uses our type cast `(DoubleUnaryOperator)` to determine the return type which, of course, must match with `inT`. – Holger Apr 08 '15 at 07:46
  • Hi, and what if the methods "op" would not be static, so reference to an instance method of an arbitrary object of a particular type. How to obtain this kind of map then? – Kristoff May 04 '20 at 08:28
  • 1
    @Kristoff you have to decide. Do you want to bind (capture) a specific instance at creation time, so it will always be used when you evaluate the `DoubleUnaryOperator`, or do you want to pass an instance (potentially being different every time) each time you evaluate the function. [this answer](https://stackoverflow.com/a/27605965/2711488) discusses both options on a single example. However, for the second case you would need a custom interface for consuming an object and a `double` and producing a `double` (unless you are ok with boxing). – Holger May 04 '20 at 08:36