import java.lang.invoke.*;
public class InvokeDynamicDemo {
public static double doubleIt(double d){
System.out.print("Doubling it");
return d*2;
}
public static void main(String[] args) throws Throwable {
MethodHandles.Lookup lookUp = MethodHandles.lookup();
MethodHandle doubleIt = lookUp.findStatic(InvokeDynamicDemo.class, "doubleIt", MethodType.methodType(double.class,double.class));
doubleIt.invokeExact(2.0D); // Exception
//doubleIt.invoke(2.0D); // No exception thrown
}
}
Exception in thread "main" java.lang.invoke.WrongMethodTypeException: expected (double)double but found (double)void at java.lang.invoke.Invokers.newWrongMethodTypeException(Invokers.java:340) at java.lang.invoke.Invokers.checkExactType(Invokers.java:351) at InvokeDynamicDemo.main(InvokeDynamicDemo.java:32)
What is wrong with this code , I can't figure it. Please help.
The problem is that you're not using the result of the invokeExact
method. I hadn't seen this method before, but it looks like the Java compiler has to handle it in a very special way. From the MethodHandle
documentation:
As is usual with virtual methods, source-level calls to invokeExact and invoke compile to an invokevirtual instruction. More unusually, the compiler must record the actual argument types, and may not perform method invocation conversions on the arguments. Instead, it must generate instructions that push them on the stack according to their own unconverted types. The method handle object itself is pushed on the stack before the arguments. The compiler then generates an
invokevirtual
instruction that invokes the method handle with a symbolic type descriptor which describes the argument and return types.To issue a complete symbolic type descriptor, the compiler must also determine the return type. This is based on a cast on the method invocation expression, if there is one, or else
Object
if the invocation is an expression, or elsevoid
if the invocation is a statement. The cast may be to a primitive type (but notvoid
).
At the moment you're calling the method without using the result, so the compiler infers that you expect it to be a void
method - hence the (double)void
part of the exception.
If you change the call to:
double result = (double) doubleIt.invokeExact(2.0);
... then the compiler knows what return type you're expecting, and can create the appropriate symbolic type descriptor.
See more on this question at Stackoverflow