I know from the Faster alternatives to Java's reflection, Using LambdaMetafactory with MethodHandle is closer to a direct call, but in my JMH program results, LambdaMetafactory is even slower than reflection, It's quite different from the previous questions. I don't know what went wrong
Here are my JMH test results,the BenchmarkMode is AverageTime
Benchmark Mode Cnt Score Error Units
MhExceptionBenchMark.MhExceptioTest.directNew avgt 10 248.059 ± 52.375 ns/op
MhExceptionBenchMark.MhExceptioTest.mhLamda avgt 10 2435.962 ± 45.767 ns/op
MhExceptionBenchMark.MhExceptioTest.mhNoLamda avgt 10 2573.739 ± 688.203 ns/op
MhExceptionBenchMark.MhExceptioTest.reflet avgt 10 2344.597 ± 237.946 ns/op
All I have to do is dynamically build a constructor with a String input and assign the value message to it
This class is called ValidException
public class ValidException extends AbstractException {
private static final long serialVersionUID = 1L;
private static final String DEFAULT_VALID_ERRCODE = "test";
public ValidException() {
super(DEFAULT_VALID_ERRCODE);
}
public ValidException(String errMessage) {
super(DEFAULT_VALID_ERRCODE, errMessage);
}
}
Its parent class is AbstractException
public abstract class AbstractException extends RuntimeException {
private static final long serialVersionUID = 1L;
private String errMessage;
public AbstractException(String errMessage) {
super(errMessage);
}
}
My JMH program is
@Fork(1)
@BenchmarkMode(Mode.AverageTime)
@Warmup(iterations = 3)
@Measurement(iterations = 10, time = 5)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Threads(10)
public class MhExceptioTest {
@State(Scope.Benchmark)
public static class Ex {
ValidException validException;
@Setup(Level.Trial)
public void prepare() {
validException = new ValidException();
}
}
@State(Scope.Benchmark)
public static class MhNoLambda{
MethodHandle methodHandle;
@Setup(Level.Trial)
public void prepare() throws NoSuchMethodException, IllegalAccessException {
MethodType methodType = MethodType.methodType(void.class, String.class);
methodHandle = MethodHandles.publicLookup().findConstructor(ValidException.class, methodType);
}
}
@State(Scope.Benchmark)
public static class MhLambda{
Function<String,AbstractException> function;
@Setup(Level.Trial)
public void prepare() throws Throwable {
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodType methodType = MethodType.methodType(void.class, String.class);
MethodHandle methodHandle = lookup.findConstructor(ValidException.class, methodType);
CallSite site = LambdaMetafactory.metafactory(
lookup,
"apply",
MethodType.methodType(Function.class),
methodHandle.type().generic(),
methodHandle,
methodHandle.type());
function = (Function<String, AbstractException>)site.getTarget().invokeExact();
}
}
@State(Scope.Benchmark)
public static class Constr{
Constructor<ValidException> constructor;
@Setup(Level.Trial)
public void prepare() throws NoSuchMethodException {
constructor = ValidException.class.getConstructor(String.class);
}
}
@Benchmark
public <T extends AbstractException> AbstractException directNew(Ex ex){
ValidException validException = ex.validException;
validException.setErrMessage("test");
return validException;
}
@Benchmark
public <T extends AbstractException> AbstractException mhNoLamda(MhNoLambda mhNoLambda) throws Throwable {
return (AbstractException) mhNoLambda.methodHandle.invoke("test");
}
@Benchmark
public <T extends AbstractException> AbstractException reflet(Constr constr) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
ValidException validException = constr.constructor.newInstance("test");
return validException;
}
@Benchmark
public <T extends AbstractException> AbstractException mhLamda(MhLambda mhLambda){
return mhLambda.function.apply("test");
}
public static void main(String[] args) throws RunnerException {
Options options = new OptionsBuilder()
.include(MhExceptioTest.class.getSimpleName())
.result("./result-mh-ex.json")
.resultFormat(ResultFormatType.JSON)
.build();
new Runner(options).run();
}
}