როგორ მუშაობს ლამბდა გამოთქმა და რა ხდება 'ქვაბზე'?
sobes.tech AI
პასუხი AI-სგან
Java-ში ლამბდა გამოთქმები მუშაობს შემდეგი მექანიზმების საშუალებით:
-
ფუნქციონალური ინტერფეისები: ლამბდა გამოთქმას უნდა მიენიჭოს ცვლადი, დაბრუნდეს მეთოდიდან ან გადაეცეს მეთოდს, რომლის ტიპიც არის ფუნქციონალური ინტერფეისი. ფუნქციონალური ინტერფეისი — ეს არის ინტერფეისი, რომელშიც მხოლოდ ერთი აბსტრაქტული მეთოდი (SAM - Single Abstract Method).
@FunctionalInterfaceანოტაცია არ არის სავალდებულო, მაგრამ რეკომენდებულია კომპილატორის მიერ შემოწმებისთვის. -
ინვოკაცია დინამიკა (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);
}
}