I'm trying to do performance testing of the below mentioned code with three scenarios by logging the execution time of a getName method of a Person Class.
- LambdaMetaFactory
- Direct Access
- Reflection
Ideally, reflection should take more time to execute than the LambdaMetaFactory. But, my output is surprising as shown below :
Lambda Exec Time :: 3510309 ns
Direct Exec Time :: 2701586 ns
Reflection Exec Time :: 10 ns
Are there any issues in the code?
My code:
package com.jpmc.util.test.reflection;
import java.lang.invoke.LambdaMetafactory;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
public class PerformanceTest {
public static void main(String args[]) throws Throwable {
//LambdaMetaFactory
var lookup = MethodHandles.lookup();
var interfaceMethodName = "invoke";
var factoryType = MethodType.methodType(GetterFunction.class);
var interfaceMethodType = MethodType.methodType(Object.class,Object.class);
var implementation = lookup.findVirtual(Person.class,"getName",MethodType.methodType(String.class));
var dynamicMethodType = MethodType.methodType(String.class,Person.class);
var factory = LambdaMetafactory.metafactory(lookup,
interfaceMethodName,
factoryType,
interfaceMethodType,
implementation,
dynamicMethodType);
var getterFunction = (GetterFunction<Person,String>) factory.getTarget().invoke();
Person person = new Person("Joe");
long startTime = System.nanoTime();
int runs = 100000;
for (int i = 0; i < runs; i++) {
getterFunction.invoke(person);
}
long endTime = System.nanoTime();
System.out.println( "Lambda Exec Time :: "+ (endTime-startTime) + " ns");
//Direct Access
{
long start = System.nanoTime();
for (int i = 0; i < runs; i++)
//direct access
person.getName();
long time = System.nanoTime() - start;
System.out.println( "Direct Exec Time :: "+ time + " ns");
}
//Reflection
Method getNameMethod = Person.class.getMethod("getName");
{
long start = System.currentTimeMillis();
for (int i = 0; i < runs; i++)
//reflection access
getNameMethod.invoke(person);
long time = System.currentTimeMillis() - start;
System.out.println( "Reflection Exec Time :: "+ time+ " ns");
}
}
}
@FunctionalInterface
interface GetterFunction<T,U> {
U invoke (T instance);
}
class Person {
String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
public String toString() {
return name;
}
}
Edited
Have understood to use benchmarking. But, is it mandatory to use benchmarking for LambdaMetaFactory to log the execution time ? Just want to get the execution time of all approaches (LambdaMetaFactory, Reflection, DirectAccess) via simple Java code.
What are the results unexpected and what changes do I need to make for desired results?