Я пытаюсь добиться максимальной производительности в одном из моих сценариев, не выполняя серьезного рефакторинга.
Я обнаружил метод, который создает BiConsumer из поля с использованием отражения.
return (c, v) -> {
try {
field.set(c, v);
} catch (final Throwable e) {
throw new RuntimeException("Could not set field: " + field, e);
}
};
Отражение имеет репутацию медленного.Поэтому я подумал, что могу использовать дескрипторы метода.
Lookup lookup = MethodHandles.lookup();
MethodHandle mh = lookup.unreflectSetter(field);
return (c, v) -> {
try {
mh.invoke(c, v);
} catch (final Throwable e) {
throw new RuntimeException("Could not set field: " + field, e);
}
};
Что уже немного быстрее.Однако BiConsumer
- это FunctionalInterface
, который может быть просто сгенерирован каким-либо образом.
public static <C, V> BiConsumer<C, V> createSetter(final MethodHandles.Lookup lookup,
final Field field) throws Exception {
final MethodHandle setter = lookup.unreflectSetter(field);
final CallSite site = LambdaMetafactory.metafactory(lookup,
"accept",
MethodType.methodType(BiConsumer.class),
MethodType.methodType(void.class, Object.class, Object.class), // signature of method BiConsumer.accept after type erasure
setter,
setter.type()); // actual signature of setter
return (BiConsumer<C, V>) site.getTarget().invokeExact();
}
Однако тогда я получаю исключение, которого я не совсем понимаю
Exception in thread "main" java.lang.invoke.LambdaConversionException: Unsupported MethodHandle kind: putField org.sample.dto.TestDTO.name:(String)void
at java.lang.invoke.AbstractValidatingLambdaMetafactory.validateMetafactoryArgs(AbstractValidatingLambdaMetafactory.java:182)
at java.lang.invoke.LambdaMetafactory.metafactory(LambdaMetafactory.java:303)
at org.sample.bench.MyBenchmark.createSetter(MyBenchmark.java:120)
at org.sample.bench.MyBenchmark.main(MyBenchmark.java:114)
Каким образомя должен генерировать этот сеттер правильно, чтобы увеличить производительность.(без фактического добавления метода установки)