Lambda ifadələri necə işləyir və 'qapağın altında' nə baş verir?
sobes.tech Süni İntellekt
AI-dan cavab
Java-da lambda ifadələri aşağıdakı mexanizmlər hesabına işləyir:
-
Funksional interfeysler: Lambda ifadəsi dəyişənə təyin edilməli, metoddan geri qaytarılmalı və ya funksional interfeys tipinə malik metodlara ötürülməlidir. Funksional interfeys tək bir abstrakt metoda (SAM - Single Abstract Method) malik interfeysdir.
@FunctionalInterfaceannotasiyası opsionaldır, lakin kompilyator tərəfindən yoxlama üçün tövsiyə olunur. -
Dinamik çağırış (invokeDynamic): Java, köhnə anonim siniflər üçün bytecode-də anonim daxili sinif yaratmaq yerinə,
invokeDynamicəmri istifadə edir. Bu əmri Java 7-də dinamik tipli dilləri JVM-də dəstəkləmək üçün əlavə olunmuşdur və Java 8-də lambda ifadələri və metod referanslarının həyata keçirilməsi üçün istifadə olunur.invokeDynamicçağırışın həllini icra zamanı (runtime) təxirə salır.
"Altında baş verənlər":
Tərcümə mərhələsində:
- Kompilyator lambda ifadəsini analiz edir.
- Lambda ilə əlaqəli funksional interfeysin tipini müəyyən edir.
- Eyni sinifdə xüsusi sintetik metod (adətən
lambda$prefiksi ilə) yaradılır, bu metod lambda ifadəsinin loqikasını ehtiva edir. Bu metod funksional interfeysin abstrakt metoduyla eyni imzaya malikdir. - Lambda istifadə olunduğu yerdə, kompilyator
invokeDynamicəmri yaradır. Bu əmrin içində bootstrap method (LambdaMetafactory.metafactory) üçün referans var.
İcrada (runtime):
- JVM
invokeDynamicəmrinə rast gələndə ilk dəfə bootstrap method (LambdaMetafactory.metafactory) çağırılır. - Bootstrap method (
LambdaMetafactory.metafactory) dinamik olaraq yaddaşda call site yaradır. - Call site, funksional interfeysi həyata keçirən sinifin nümunəsini yaradır və geri qaytarır. Bu nümunə:
- İstənilən vaxt yaradılmış ola bilər (məsələn,
Constant CallSiteistifadə edilərək). - Sonrakı istifadə üçün cache-lənə bilər (stateless lambda üçün).
- Artıq mövcud olan nümunəyə istinad kimi təqdim oluna bilər (məsələn,
Serializableilə stateless lambda üçün).
- İstənilən vaxt yaradılmış ola bilər (məsələn,
- Yaradılan sinif, funksional interfeys metodunun çağırışını, kompilyator tərəfindən yaradılmış sintetik metod (
lambda$) vasitəsilə həyata keçirir. - Birinci çağırışdan sonra, bootstrap method yaddaşda hansı obyektin geri qaytarılacağını qeyd edir və növbəti
invokeDynamicçağırışları bu obyektə sürətli şəkildə çıxış edə və ya birbaşa çağırış edə bilər, yenidən bootstrap method çağırmadan.
Beləliklə, lambda-lar hər dəfə yeni sinif yaratmır. Variablları xarici kontekstdən (stateless lambda) tutmayan lambda-lar üçün, funksional interfeysin həyata keçirilməsi singleton və ya yadda saxlanılan instansiya ola bilər. Variablları tutan lambda-lar (stateful lambda) yeni sinif nümunəsinin yaradılmasını tələb edir.
invokeDynamic istifadə etməklə JIT-compiler, funksional interfeys metod çağırışlarını ənənəvi anonim sinif modellərindən daha səmərəli optimallaşdıra bilər, çünki JIT icra zamanı daha məlumatlı qərarlar qəbul edə bilər.
// Funksional interfeys nümunəsi
@FunctionalInterface
interface MyFunction {
String apply(String input);
}
public class LambdaExample {
public static void main(String[] args) {
// Lambda ifadəsindən istifadə
MyFunction func = s -> "Processed: " + s;
String result = func.apply("Test");
System.out.println(result);
}
}