Method handles (хэндл метод, методические обработчики)
Рефлексия (Reflection) - - это мощная техника для выполнения действий во время выполнения, но у нее есть ряд недостатков в конструкции (здесь можно проводить мудрые выводы впоследствии), и сейчас она определенно устарела. Одной из ключевых проблем рефлексии является производительность, особенно потому, что рефлективные вызовы трудно встраивать в компилятор Just-In-Time - "точно в срок" (JIT).
Это плохо, потому что встраивание очень важно для JIT-компиляции по нескольким причинам, не наименее важная из которых заключается в том, что встраивание обычно является первой оптимизацией, которая применяется, и оно открывает двери для других техник (таких как анализ побегов и устранение мертвого кода).
Вторая проблема заключается в том, что рефлексивные вызовы связываются каждый раз, когда обнаруживается место вызова Method.invoke(). Это означает, например, что выполняются проверки доступа к безопасности. Это очень расточительно, потому что эта проверка, как правило, либо успешна, либо не успешна при первом вызове, и если она успешна, то будет продолжаться в течение всей жизни программы. Однако рефлексия снова и снова выполняет эту связывание. Таким образом, рефлексия несет много ненужных издержек на перелинковку и потерю вычислительного времени.
Для решения этих (и других) проблем в Java 7 появилось новое API, java.lang.invoke, которое часто вскользь называют "методическими обработчиками" (хэндл метод, MH) из-за названия главного класса, введенного в этом API.
Хэндл метод (MH) - это версия безопасного указателя функции с сохранением типа в Java. Это способ ссылаться на метод, который код может захотеть вызвать, аналогично объекту Method из рефлексии Java. У MH есть метод invoke(), который фактически выполняет базовый метод, так же, как рефлексия.
На одном уровне MH - это просто более эффективный механизм рефлексии, который ближе к низкоуровневому; все, что представлено объектом из Reflection API, может быть преобразовано в эквивалентный MH. Например, объект рефлексии Method может быть преобразован в MH с помощью Lookup.unreflect(). Созданные MH обычно являются более эффективным способом доступа к базовым методам.
MH могут быть адаптированы с помощью вспомогательных методов класса MethodHandles различными способами, такими как композиция и частичное связывание аргументов метода ("каррирование" - currying).
Обычно связывание методов требует точного совпадения дескрипторов типов. Однако метод invoke() в MH имеет специальную полиморфную сигнатуру, которая позволяет выполнять связывание независимо от сигнатуры вызываемого метода.
Во время выполнения сигнатура на месте вызова invoke() должна выглядеть так, как будто вы вызываете целевой метод напрямую, что позволяет избежать преобразования типов и затрат на автобоксинг, характерных для рефлексивных вызовов.
Поскольку Java является статически типизированным языком, возникает вопрос о том, насколько можно сохранить безопасность типов при использовании такого фундаментально динамического механизма. В API MH этот вопрос решается с помощью типа MethodType, который представляет собой неизменяемое представление аргументов, принимаемых методом: сигнатуру метода.
Внутренняя реализация MH была изменена в ходе развития Java 8. Новая реализация называется лямбда-формами, и она обеспечила значительное повышение производительности: теперь MH более эффективны, чем рефлексия, во многих случаях использования.