Sobes.tech
Middle+

როგორ მუშაობს ლამბდა გამოთქმა და რა ხდება 'ქვაბზე'?

sobes.tech AI

პასუხი AI-სგან

Java-ში ლამბდა გამოთქმები მუშაობს შემდეგი მექანიზმების საშუალებით:

  1. ფუნქციონალური ინტერფეისები: ლამბდა გამოთქმას უნდა მიენიჭოს ცვლადი, დაბრუნდეს მეთოდიდან ან გადაეცეს მეთოდს, რომლის ტიპიც არის ფუნქციონალური ინტერფეისი. ფუნქციონალური ინტერფეისი — ეს არის ინტერფეისი, რომელშიც მხოლოდ ერთი აბსტრაქტული მეთოდი (SAM - Single Abstract Method). @FunctionalInterface ანოტაცია არ არის სავალდებულო, მაგრამ რეკომენდებულია კომპილატორის მიერ შემოწმებისთვის.

  2. ინვოკაცია დინამიკა (invokeDynamic): Байტკოდში ანონიმური შიდა კლასის გენერაციის ნაცვლად, Java იყენებს invokeDynamic ბრძანებას. ეს ბრძანება დამატებულია Java 7-ში, რათა მხარდაჭერა მიეცეს დინამიკულად ტიპიზირებულ ენებს JVM-ზე, ხოლო Java 8-ში ის გამოიყენება ლამბდა გამოთქმებისა და მეთოდების ბმულების განხორციელებისთვის. invokeDynamic გამოიწვევს მეთოდის გამოძახების გადაწყვეტას შესრულების დროს (runtime).

რა ხდება "ქვეშა კოდში":

კომპილაციის ეტაპზე:

  • კომპილატორი ანალიზს ახდენს ლამბდა გამოთქმაზე.
  • განსაზღვრავს ფუნქციონალური ინტერფეისის ტიპს, რომელსაც ლამბდა მიენიჭება.
  • გენერირდება სპეციალური სინთეტიკური მეთოდი (სხვადასხვა სახელით, ხშირად lambda$), რომელიც იმავე კლასშია, სადაც ლამბდაა. ამ მეთოდს აქვს იგივე სიგნატურა, რაც ფუნქციონალური ინტერფეისის აბსტრაქტულ მეთოდს.
  • ლამბდა გამოყენების ადგილას, კომპილატორი გენერირებს invokeDynamic ბრძანებას. ეს ბრძანება შეიცავს ბუტსტრაპ მეთოდის (LambdaMetafactory.metafactory) ლინკს.

შესრულების ეტაპზე (runtime):

  • როდესაც JVM ხვდება invokeDynamic ბრძანებას, ის პირველად იძახის ბუტსტრაპ მეთოდს (LambdaMetafactory.metafactory).
  • ბუტსტრაპ მეთოდი დინამიკურად ქმნის მეხსიერებაში call site-ს.
  • call site ქმნის და აბრუნებს იმ კლასის ინსტანსს, რომელიც რეალიზებს ფუნქციონალურ ინტერფეისს. ეს ინსტანსი შეიძლება იყოს:
    • შექმნილი ლაიტ-თაიმ (მაგ., Constant CallSite-ის გამოყენებით),
    • კეშირებული (stateless ლამბდებისთვის),
    • ან უკვე არსებულ ინსტანსზე მითითება (მაგ., Serializable-ს რეალიზებადი stateless ლამბდებისთვის).
  • ეს გენერირებული კლასი დელეგირებს აბსტრაქტულ მეთოდს გენერირებულ სინთეტიკურ მეთოდზე (lambda$).
  • პირველი bootstrap-ის გამოძახებიდან, call site იძენს რა ობიექტი უნდა დაბრუნდეს, და შემდეგი invokeDynamic-ები სწრაფად იღებს ამ ობიექტს ან პირდაპირ იძახის მას, გარეშე მეორედ bootstrap-ის გამოძახების.

ამით, ლამბდა-გამოთქმები არ ქმნის ყოველ ინსტანსი ახალი კლასი. სტატლეს ლამბდებისთვის, ფუნქციონალური ინტერფეისის რეალიზაცია შეიძლება იყოს სინგლტონი ან კეშირებული ობიექტი, რომელიც გამოიყენება მეორედ. სტეტფულ ლამბდებს სჭირდება ახალი ინსტანსის შექმნა, რომელიც შეინახავს დაკავებულ ცვლილებებს.

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);
    }
}