Sobes.tech
Middle+

Kā darbojas lambda izteiksmes un kas notiek 'zem motora pārsega'?

sobes.tech AI

Atbilde no AI

Java līmda izteiksmes darbojas ar šādiem mehānismiem:

  1. Funkcionālie interfeisi: Līmdas izteiksmei jābūt piešķirtai mainīgajam, jāatgriežas no metodes vai jānodod metodei, kuras tips ir funkcionālais interfeiss. Funkcionālais interfeiss ir interfeiss ar tieši vienu abstraktu metodi (SAM - Single Abstract Method). Anotācija @FunctionalInterface ir izvēles, bet ieteicama kompilatora pārbaudei.

  2. Dinamisks izsaukums (invokeDynamic): Tā vietā, lai ģenerētu anonīmu iekšējo klasi baitkoda laikā, kā tas bija vecākās anonīmo klasu versijās, Java izmanto invokeDynamic instrukciju. Šī instrukcija tika pievienota Java 7, lai atbalstītu dinamiski tipizētas valodas JVM, un Java 8 tā tiek izmantota līmda izteiksmju un metožu saistīšanas īstenošanai. invokeDynamic atliek metodes izsaukuma risināšanu līdz izpildes laikam (runtime).

Kas notiek "zem pārsega":

Kompilācijas laikā:

  • Kompilators analizē līmda izteiksmi.
  • Nosaka funkcionālā interfeisa tipu, kam tā tiek piešķirta.
  • Ģenerē īpašu sintētisku metodi (bieži ar lambda$ prefiksu) tajā pašā klasē, kurā ir līmda loģika. Šī metode ir ar tādu pašu signatūru kā funkcionālā interfeisa abstraktā metode.
  • Līmdas izmantošanas vietā kompilators ģenerē invokeDynamic instrukciju. Šī instrukcija satur atsauci uz bootstrap metodi (LambdaMetafactory.metafactory).

Izpildes laikā:

  • Kad JVM sastop invokeDynamic, tas pirmo reizi izsauc bootstrap metodi (LambdaMetafactory.metafactory).
  • Bootstrap metode dinamiski ģenerē atmiņā call site.
  • Call site izveido un atgriež klases instanci, kas īsteno funkcionālo interfeisu. Šis instances var būt:
    • izveidots uz vietas (piemēram, ar ģenerētu Constant CallSite),
    • kešots (stateless līmda),
    • vai attēlots kā atsauce uz jau esošu funkcionālo interfeisa instanci (piemēram, stateless līmda, kas realizē Serializable).
  • Šī ģenerētā klase deleģē abstraktās metodes izsaukumu ģenerētajam sintētiskajam metodam (lambda$).
  • Pēc pirmās bootstrap izsaukšanas, call site atceras, kādu objektu vajag atgriezt, un nākamie invokeDynamic izsaukumi var ātri saņemt šo objektu vai tieši izsaukt to bez atkārtotas bootstrap izsaukšanas.

Tādējādi līmda izteiksmes dažreiz neveido jaunu klasi katrai instancēšanai. Stateless līmda var būt kā singleton vai kešots objekts, kas tiek atkārtoti izmantots. Stāvoklī līmda, kas ietver mainīgos, prasa jauna objekta izveidi, kas glabās iekļautos mainīgos.

invokeDynamic izmantošana ļauj JIT-kompilatoram optimizēt funkciju interfeisa metožu izsaukumus efektīvāk nekā tradicionālais anonimās klases modelis, jo JIT var pieņemt informētākus lēmumus izpildes laikā.

// Funkcionālais interfeiss piemērs
@FunctionalInterface
interface MyFunction {
    String apply(String input);
}

public class LambdaExample {
    public static void main(String[] args) {
        // Līmdas izteiksmes izmantošana
        MyFunction func = s -> "Processed: " + s;

        String result = func.apply("Test");
        System.out.println(result);
    }
}