I would like to call a method via reflection in the most performant way possible.
The method returns an Object.
I've implemented this using both reflection and MethodHandles, I was expecting MethodHandle to be faster - but that's not what I'm seeing (~20-40% slower).
Take the following JMH benchmark:
import org.openjdk.jmh.annotations.*;import java.lang.invoke.MethodHandle;import java.lang.invoke.MethodHandles;import java.lang.reflect.Method;import java.util.concurrent.TimeUnit;import java.util.concurrent.atomic.AtomicInteger;@BenchmarkMode(Mode.AverageTime)@OutputTimeUnit(TimeUnit.NANOSECONDS)@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)@Measurement(iterations = 200, time = 10, timeUnit = TimeUnit.MILLISECONDS)@State(Scope.Benchmark)public class AccessorBenchmark { private static final Object[] EMPTY_ARGS = new Object[0]; private POJO source; private Method method; private MethodHandle methodHandle; private MethodHandle methodHandleModifiedReturnType; @Setup public void setup() throws ReflectiveOperationException { source = new POJO(); method = source.getClass().getDeclaredMethod("getNumber"); methodHandle = MethodHandles.lookup().unreflect(method); methodHandleModifiedReturnType = methodHandle.asType(methodHandle.type().changeReturnType(Number.class)); } @Benchmark public Number reflection() throws Throwable { return (Number) method.invoke(source, EMPTY_ARGS); } @Benchmark public Number methodHandle() throws Throwable { return (Number) methodHandle.invoke(source); } @Benchmark public Number methodHandleInvokeExact() throws Throwable { return (Number) methodHandleModifiedReturnType.invokeExact(source); } public class POJO { private final AtomicInteger counter = new AtomicInteger(); public AtomicInteger getNumber() { return counter; } }}
The following result is returned with Java 17:
Benchmark Mode Cnt Score Error UnitsAccessorBenchmark.methodHandle avgt 1000 2.856 ± 0.004 ns/opAccessorBenchmark.methodHandleInvokeExact avgt 1000 2.359 ± 0.003 ns/opAccessorBenchmark.reflection avgt 1000 2.017 ± 0.002 ns/op
Any ideas?