В java 7 появилось новое апи для вызова методов - MethodHandle. В этом посте обсудим его составные части, разницу с Reflection, и где MethodHandle может пригодится.
В чём разница с Reflection API?
MethodHandle выполняет проверки типов, доступов и тд всего один раз - во время создания. Собственно для этого метод хэндл и создавался - оптимизировать вызов методов, неизвестных во время компиляции.
Reflection делает все операции при каждом вызове.
Чем больше вызовов - тем сильнее разница. В OpenJDK даже есть JEP "Переписать реализацию Reflection API на MethodHandle", что говорит о многом.
Как им пользоваться?
1️⃣ Получаем фабрику для будущих метод хэндлов
Lookup pl = MethodHandles.publicLookup();2️⃣ Задаём сигнатуру метода
MethodType mt = MethodType.methodType(String.class, Integer.class, Long.class);Первый аргумент (String.class) - это возвращаемое значение, остальные - входные параметры.
3️⃣ Получаем указатель на метод
MethodHandle mh = all.findVirtual(User.class, "findName", mt);Это ссылка на метод findName в классе User, который принимает на вход два параметра и возвращает String.
4️⃣ Подставляем аргументы и вызываем
String res = mh.invoke(1, 2L);Выбор методов на каждом этапе гораздо шире, но разбирать мы их, конечно, не будем.
Где пригодится MethodHandle?
Конечно же в библиотеках и фреймворках, которые работают с аннотациями. Но для энтерпрайза у MethodHandle тоже есть микро-кейс: объявление логгера.
Ну вы знаете, в классах бизнес-логики часто добавляют логгирование:
LoggerFactory.getLogger(AccountService.class);Эта строка копируется из класса в класс, меняется только имя в скобках. Операция настолько простая, что можно забыть это сделать🙂
Если использовать MethodHandle:
Logger.getLogger(MethodHandles.lookup().lookupClass());то можно спокойно копировать строчку и ничего не менять.
В целом основная миссия MethodHandle - работать в паре с invokedynamic. Но об этом чуть позже🙂