Ламбда билдирүүлөрү кандай иштейт жана 'капоттун астында' эмне болот?
sobes.tech AI
AIден жооп
Javaда лямбда-экспрессиялар төмөнкү механизмдер аркылуу иштейт:
-
Функционалдык интерфейстер: Лямбда-экспрессия өзгөрмөгө берилиши, методтон кайтарылышы же методго өткөрүлүшү керек, анын тиби функционалдык интерфейс болушу керек. Функционалдык интерфейс — бул бир гана абстракттуу методду (SAM - Single Abstract Method) камтыган интерфейс.
@FunctionalInterfaceаннотациясы милдеттүү эмес, бирок компилятор тарабынан текшерүү үчүн сунушталат. -
Инвокация динамикасы (invokeDynamic): Байткоддо аноним ички класс түзүүнүн ордуна, Java
invokeDynamicкомандасын колдонуп жатат. Бул команда Java 7де JVMдеги динамикалык типтелген тилдерди колдоо үчүн кошулду жана Java 8де лямбда-экспрессиялар жана метод шилтемелерин ишке ашыруу үчүн колдонулат.invokeDynamicчакыруу убактысында (runtime) чечилет.
Негизги иштөө процесси:
Компиляция учурунда:
- Компилятор лямбда-экспрессияны анализдейт.
- Лямбдага ылайык келген функционалдык интерфейс тиби аныкталат.
- Лямбда логикасы камтылган атайын синтетикалык метод (көбүнчө
lambda$префикси менен) ошол класста түзүлөт. Бул метод абстракттуу метод менен бирдей сигнатурага ээ. - Лямбда колдонулган жеринде компилятор
invokeDynamicкомандасын генерейт. Бул командаbootstrap method(LambdaMetafactory.metafactory) шилтемесин камтыйт.
Ишке ашыруу учурунда:
- JVM
invokeDynamicкомандасын көргөндө, ал биринчи жолуbootstrap method-ти чакырат. bootstrap method(LambdaMetafactory.metafactory) динамикалык түрдө жаддаcall siteтүзөт.- Чакыруучу жүктөгүч (call site) функционалдык интерфейсин ишке ашыратган классинин экземплярин түзүп, кайтарат. Ал экземпляр:
- түзүлгөн (мисалы,
Constant CallSiteаркылуу), - кэштелген (стейтлесс лямбда үчүн),
- же мурдагы экземплярга шилтеме катары көрсөтүлүшү мүмкүн.
- түзүлгөн (мисалы,
- Бул түзүлгөн класс абстракттуу методду генерирленген синтетикалык методго (
lambda$) делегаттайт. - Биринчи
bootstrapчакыргандан кийин, call site кайсы объект керек экенин эстеп калат жана кийинкиinvokeDynamicчакыруулары тезирек ошол объектти алууга же түздөн-түз чакырууга мүмкүндүк берет.
Ошентип, лямбда-экспрессиялар ар бир инстанция үчүн жаңы класс түзбөйт. Стейтлесс лямбда-экспрессиялар үчүн, функционалдык интерфейсдин реализациясы singleton же кэштелген инстанс болушу мүмкүн. Стейттүү лямбда-экспрессиялар жаңы экземпляр түзүүнү талап кылат, ал захваченные өзгөрмөлөрдү сактайт.
invokeDynamic колдонуу JIT-кампиляторго функциялык интерфейс методдорунун чакырууларын натыйжалуу оптимизациялоого мүмкүндүк берет, анткени JIT ишке ашыруу учурунда көбүрөөк маалыматка ээ болот.
// Функционалдык интерфейс мисалы
@FunctionalInterface
interface MyFunction {
String apply(String input);
}
public class LambdaExample {
public static void main(String[] args) {
// Лямбда-экспрессияны колдонуу
MyFunction func = s -> "Processed: " + s;
String result = func.apply("Test");
System.out.println(result);
}
}