Лямбда-выражения в Java работают за счет следующих механизмов:
Функциональные интерфейсы: Лямбда-выражение должно быть присвоено переменной, возвращено из метода или передано в метод, тип которого является функциональным интерфейсом. Функциональный интерфейс — это интерфейс с ровно одним абстрактным методом (SAM - Single Abstract Method). Аннотация @FunctionalInterface является опциональной, но рекомендуется для проверки компилятором.
Инвокация динамики (invokeDynamic): Вместо генерации анонимного внутреннего класса в байткоде на этапе компиляции, как это делалось для старых версий анонимных классов, Java использует инструкцию invokeDynamic. Эта инструкция была добавлена в Java 7 для поддержки динамически типизированных языков на JVM, а в Java 8 используется для реализации лямбда-выражений и ссылок на методы. invokeDynamic откладывает разрешение вызова метода до момента выполнения (runtime).
Что происходит 'под капотом':
На этапе компиляции:
lambda$) в том же классе, который содержит логику лямбда-выражения. Этот метод имеет такую же сигнатуру, как и абстрактный метод функционального интерфейса.invokeDynamic. Эта инструкция содержит ссылку на bootstrap method (LambdaMetafactory.metafactory).На этапе выполнения (runtime):
invokeDynamic, она первый раз вызывает bootstrap method (LambdaMetafactory.metafactory).LambdaMetafactory.metafactory) динамически генерирует в памяти загрузчик вызова (call site).Constant CallSite).Serializable).lambda$).invokeDynamic для той же лямбды могут быстро получить этот объект или вызвать его напрямую без повторного вызова bootstrap method.Таким образом, лямбды не всегда создают новый класс на каждую инстанциацию. Для лямбд, которые не захватывают переменные из внешнего контекста (stateless лямбды), реализация функционального интерфейса может быть синглтоном или инстансом, который кешируется и повторно используется. Лямбды, захватывающие переменные (stateful лямбды), требуют создания нового экземпляра класса, который будет хранить захваченные переменные.
Использование invokeDynamic позволяет JIT-компилятору оптимизировать выполнение вызовов методов функционального интерфейса более эффективно, чем традиционная модель анонимных классов, поскольку JIT может принимать более информированные решения во время выполнения.
java