Лямбда-выражения в Java работают на основе нескольких ключевых концепций и механизмов, включая функциональные интерфейсы, инструкции
invokedynamic, и использование java.lang.invoke.MethodHandle и java.lang.invoke.LambdaMetafactory. 🚩Основные компоненты
🟠Функциональные интерфейсы
Лямбда-выражения могут использоваться только в контексте функционального интерфейса. Функциональный интерфейс — это интерфейс, который имеет только один абстрактный метод. Примеры функциональных интерфейсов:
Runnable, Callable, Comparator, и интерфейсы из пакета java.util.function (Function, Predicate, Consumer, Supplier).🟠Инструкция `invokedynamic`
invokedynamic — это инструкция байт-кода, введенная в Java 7, которая позволяет динамически связывать вызовы методов во время выполнения. В случае лямбда-выражений, invokedynamic используется для создания инстанции функционального интерфейса.🟠`java.lang.invoke.MethodHandle` и `java.lang.invoke.LambdaMetafactory`
MethodHandle — это легковесный, типобезопасный способ описания подлежащих вызову методов, конструкторов и полей. LambdaMetafactory — это утилита, используемая JVM для создания реализации функционального интерфейса на основе лямбда-выражения. При выполнении инструкции invokedynamic JVM вызывает LambdaMetafactory для создания экземпляра функционального интерфейса.🚩Пример работы лямбда-выражения под капотом
1⃣Написание лямбда-выражения
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.forEach(name -> System.out.println(name));2⃣Компиляция лямбда-выражения
Компилятор преобразует лямбда-выражение в байт-код, который использует инструкцию
invokedynamic. Инструкция invokedynamic указывает на метод-обработчик (MethodHandle) для метода System.out.println(name).3⃣Выполнение лямбда-выражения
При выполнении инструкции
invokedynamic JVM вызывает LambdaMetafactory для создания инстанции функционального интерфейса Consumer<String>. LambdaMetafactory создает реализацию интерфейса Consumer<String> с методом accept, который вызывает System.out.println(name).🚩Преобразование лямбда-выражения
// Лямбда-выражение
Consumer<String> consumer = name -> System.out.println(name);
// Компилируется в байт-код, который использует invokedynamic
Consumer<String> consumer = (Consumer<String>) LambdaMetafactory.metafactory(
caller,
"accept",
MethodType.methodType(Consumer.class),
MethodType.methodType(void.class, Object.class),
MethodHandles.lookup().findVirtual(System.out.getClass(), "println", MethodType.methodType(void.class, String.class)),
MethodType.methodType(void.class, String.class)
).getTarget().invoke();
🚩Плюсы
➕Компактность
Лямбда-выражения позволяют писать более компактный и читаемый код.
➕Производительность
Использование
invokedynamic и LambdaMetafactory позволяет JVM генерировать высокоэффективный байт-код для лямбда-выражений.➕Гибкость
Лямбда-выражения могут использоваться в любых контекстах, где ожидается функциональный интерфейс.
Ставь 👍 и забирай 📚 Базу знаний