CodeGym /Kurslar /Java SELF AZ /Lambda ifadələrinin yaranma tarixçəsi

Lambda ifadələrinin yaranma tarixçəsi

Java SELF AZ
Səviyyə , Dərs
Mövcuddur

1. İnterfeyslər

Lambda funksiyaların nə olduğunu başa düşmək üçün əvvəlcə interfeyslərin nə olduğunu başa düşmək lazımdır. Ona görə də əsas məqamları xatırladaq.

İnterfeys — bu, sinif növüdür. Çəkilmiş formada, desək belə olar. İnterfeysin, sinifdən fərqli olaraq, öz dəyişənləri ola bilməz (statiklərdən başqa). Həmçinin İnterfeys tipində obyektlər yaradıla bilməz:

  • Sinif dəyişənləri elan olunmur
  • Obyektlər yaradıla bilməz

Nümunə:

interface Runnable
{
   void run();
}
siniflər bu interfeysi reallaşdırır.

Əgər bir sinif interfeysi reallaşdırırsa, interfeysdə elan edilmiş, lakin reallaşdırılmamış metodları öz daxilində mütləq reallaşdırmalıdır. Nümunə:

interface Runnable
{
   void run();
}

class Timer implements Runnable
{
   void run()
   {
      System.out.println(LocalTime.now());
   }
}

class Calendar implements Runnable
{
   void run()
   {
      var date = LocalDate.now();
      System.out.println("Bugün " + date.getDayOfWeek());
   }
}

Timer sinifi Runnable interfeysini (implements) reallaşdırır, buna görə də interfeysdə Runnable olan bütün metodları öz daxilində elan etməyə və onları reallaşdırmağa məcburdur: metodun daxilinə kod yazmaq. Bu, Calendar sinfinə də aiddir.

Amma indi Runnable tipli dəyişənlərdə Runnable interfeysini reallaşdıran siniflərin obyektlərinə istinadlar saxlamaq mümkündür.

Nümunə:

Kod Qeyd
Timer timer = new Timer();
timer.run();

Runnable r1 = new Timer();
r1.run();

Runnable r2 = new Calendar();
r2.run();

run() metodu Timer sinfi tərəfindən çağırılacaq


run() metodu Timer sinfi tərəfindən çağırılacaq


run() metodu Calendar sinfi tərəfindən çağırılacaq

Siz həmişə obyektin sinif-atasından birini dəyişən tipinə göstərərək istinad təyin edə bilərsiniz. TimerCalendar sinifləri üçün belə tiplər ikidir: ObjectRunnable.

Əgər obyektə Object tipində bir dəyişən təyin etsəniz, yalnız Object sinfində elan edilmiş metodları çağıra biləcəksiniz. Amma əgər obyektə Runnable tipində bir dəyişən təyin etsəniz, Runnable tipində olan metodları çağıra biləcəksiniz.

Nümunə 2:

ArrayList<Runnable> list = new ArrayList<Runnable>();
list.add (new Timer());
list.add (new Calendar());

for (Runnable element: list)
    element.run();

Belə bir kod işləyəcək, çünki TimerCalendar obyektlərinin işləyən run metodları var. Buna görə də onları çağırmaqda heç bir problem yoxdur. Əgər sadəcə hər iki sinfə run() metodu əlavə etsəydik, onları belə sadə şəkildə çağıra bilməzdik.

Runnable interfeysi faktiki olaraq run metodunun yerləşdirilməsi üçün istifadə edilir.



2. Sıralama

Keçək daha praktiki bir şeyə. Məsələn, sətir sıralamasını nəzərdən keçirək.

Java-da sətir kolleksiyasını əlifba sırasına görə sıralamaq üçün əla bir metod var — Collections.sort(kolleksiya);

Bu statik metod ötürülən kolleksiyanı sıralayır və sıralama zamanı elementləri tək-tək müqayisə edir: elementləri yerlərindən dəyişmək lazımdırmı, yoxsa yox - bunu başa düşmək üçün.

Sıralama zamanı elementlərin müqayisəsi compareTo() metodu ilə həyata keçirilir, hansı ki bütün standart siniflərdə mövcuddur: Integer, String, ...

compareTo() metodu olan Integer sinifi iki rəqəmin dəyərini müqayisə edir, String sinifindəki compareTo() metodu isə sətirlərin əlifba sırasını nəzərdən keçirir.

Beləliklə, rəqəmlər kolleksiyası onların artan qaydada yerləşdiriləcək, sətirlər isə əlifba sırasına görə sıralanacaq.

Alternativ sıralama

Bəs biz sətirləri əlifba ilə deyil, onların uzunluğuna görə sıralamaq istəsək? Və rəqəmləri azalma qaydasında sıralamaq istəyirik. Bu vəziyyətdə nə etməli?

Bunun üçün Collections sinifində daha bir metod var sort(), amma artıq iki parametr ilə:

Collections.sort(kolleksiya, komparator);

Burada komparator — xüsusi obyektdir ki, kolleksiyadakı obyektləri sıralama prosesində necə müqayisə etməyi bilir. Komparator İngilis dilində Comparator (müqayisə edici) sözündən gəlir, Comparator isə Compare (müqayisə etmək) sözündən.

Bəs o necə bir xüsusi obyekt ki?

Comparator interfeysi

Əslində hər şey çox sadədir. sort() metodunun ikinci parametri — Comparator<T> tiplidir

Burada T — tip-parametrdir, kolleksiyadakı elementlərin tipi ilə eynidir, və Comparator — tək bir metodu olan interfeysdir: int compare(T obj1, T obj2);

Başqa sözlə, komparator obyekti — bu interfeysi həyata keçirən hər hansı sinifin obyektidir. Comparator interfeysi çox sadə görünür:

public interface Comparator<Tip>
{
   public int compare(Tip obj1, Tip obj2);
}
Comparator interfeysinin kodu

compare() metodu ona ötürülən iki parametri müqayisə edir.

Əgər metod mənfi sayı qaytarırsa, demək obj1 < obj2. Əgər metod müsbət sayı qaytarırsa, demək obj1 > obj2. Əgər metod 0 qaytarırsa, onda obj1 == obj2 olaraq qəbul edilir.

Uzunluqlarına görə sətirləri müqayisə edən komparator obyekti belə görünəcək:

public class StringLengthComparator implements Comparator<String>
{
   public int compare (String obj1, String obj2)
   {
      return obj1.length() - obj2.length();
   }
}
StringLengthComparator sinifinin kodu

Sətirlərin uzunluqlarını müqayisə etmək üçün sadəcə birinin uzunluğunu digərindən çıxmaq kifayətdir.

Sətirləri uzunluğuna görə sıralayan proqramın tam kodu belə görünəcək:

public class Solution
{
   public static void main(String[] args)
 {  ArrayList<String> list = new ArrayList<String>();  Collections.addAll(list, "Salam", "necesen", "işlər necədir?");  Collections.sort(list, new StringLengthComparator());  } }  class StringLengthComparator implements Comparator<String> {  public int compare (String obj1, String obj2)  {  return obj1.length() - obj2.length();  } }
Sətirlərin uzunluğuna görə sıralanması


3. Sintaktik şirinlik

Bəs necə düşünürsünüz, bu kodu daha qısa yazmaq olar? Əsasən burada yalnız bir sətir var ki, o faydalı məlumat gətirir — obj1.length() - obj2.length();.

Ancaq kod metoddan kənarda mövcud ola bilməz, buna görə compare() metodunu əlavə etmək lazım oldu və metod üçün yeni bir sinif əlavə etməli olduq — StringLengthComparator. Üstəlik dəyişənlərin tiplərini göstərmək də lazımdır... Ümumilikdə, hər şey düzgün kimi görünür.

Amma, bu kodu daha da qısa yazmaq yolları var. Sizin üçün bir az sintaktik şirinlik hazırlamışıq. Vedrə ilə, təxminən iki dənə!

Anonim daxili sinif

Comparator kodunu birbaşa main() metodunun daxilində yaza bilərsiniz və kompilyator qalan hər şeyi özü edəcək. Nümunə:

public class Solution
{
    public static void main(String[] args)
 {  ArrayList<String> list = new ArrayList<String>();  Collections.addAll(list, "Salam", "necəsən", "necəsiniz?");  Comparator<String> comparator = new Comparator<String>()  {  public int compare (String obj1, String obj2)  {  return obj1.length() - obj2.length();  }  };  Collections.sort(list, comparator);  } }
Sətirlərin uzunluğuna görə sıralanması

İnterfeysin bir obyektini yarada bilərsiniz Comparator, sinfi yaratmadan! Kompilyator onu avtomatik olaraq yaradacaq və ona hər hansı müvəqqəti ad verəcək. Müqayisə edin:

Comparator<String> comparator = new Comparator<String>()
{
    public int compare (String obj1, String obj2)
    {
        return obj1.length() - obj2.length();
    }
};
Anonim daxili sinif
Comparator<String> comparator = new StringLengthComparator();

class StringLengthComparator implements Comparator<String>
{
    public int compare (String obj1, String obj2)
    {
        return obj1.length() - obj2.length();
    }
}
StringLengthComparator sinfi

Eyni rəngdə boyanmış kod blokları iki müxtəlif halda eynidir. Əslində fərqlər çox azdır.

Kompilyator kodda birinci kod blokuna rast gələndə sadəcə ikinci blok kodu onun üçün yaradacaq və sinifə hər hansı təsadüfi ad verəcək.


4. Java-da Lambda ifadələri

Tutaq ki, kodda anonim daxili class istifadə etməyi qərara aldınız. Bu halda sizin belə bir kod blokunuz olacaq:

Comparator<String> comparator = new Comparator<String>()
{     public int compare (String obj1, String obj2)
    {
        return obj1.length() - obj2.length();
    }
};
Anonim daxili class

Burada həm dəyişənin təyinatı, həm də anonim classın yaradılması birlikdədir. Amma bu kodu yazmağın daha qısa bir yolu var. Məsələn, belə:

Comparator<String> comparator = (String obj1, String obj2) ->
{
    return obj1.length() - obj2.length();
};

Nöqtəli vergül vacibdir, çünki burada yalnız gizli class təyinatı deyil, həm də dəyişən yaradılması var.

Bu yazılış lambda ifadəsi adlanır.

Əgər kompilyator belə bir yazını kodda görsə, sadəcə olaraq onun əsasında tam versiyanı (anonim daxili class ilə) yaradacaq.

Nəzərə alın: lambda ifadəsini yazarkən biz yalnız Comparator<String> classının adını deyil, həm də int compare() metodunun adını buraxmışıq.

Kompilyatorun metodu müəyyən etməkdə heç bir problemi olmayacaq, çünki lambda ifadəsi yalnız bir metodu olan interfeyslər üçün yazıla bilər. Amma bu qaydanı keçməyin bir yolu var, bunu OOP-ni daha fəal öyrənməyə başlayanda öyrənəcəksiniz (söhbət default metodlardan gedir).

Gəlin kodun tam versiyasına bir daha baxaq, lakin burada gray rəng ilə göstərək hansı hissəni lambda ifadəsini yazarkən buraxa bilirik:

Comparator<String> comparator = new Comparator<String>()
{
    public int compare (String obj1, String obj2)
    {
      return obj1.length() - obj2.length();
    }
};
Anonim daxili class

Görünür, vacib heç bir şey buraxılmayıb. Doğrudan da, əgər Comparator interfeysində yalnız bir metod compare() varsa, qalan kodla kompilyator gray kodu bərpa edə bilər.

Sıralama

Bu arada, sıralama çağırış kodunu indi belə yazmaq olar:

Comparator<String> comparator = (String obj1, String obj2) ->
{
   return obj1.length() - obj2.length();
};
Collections.sort(list, comparator);

Hətta belə də ola bilər:

Collections.sort(list, (String obj1, String obj2) ->
   {
      return obj1.length() - obj2.length();
   }
);

Biz sadəcə olaraq comparator dəyişəni yerinə dərhal ona təyin olunan dəyəri yazdıq.

Tiplərin təxmini

Ancaq bu hələ hər şey deyil. Kod bu nümunələrdə daha da qısa yazıla bilər. Birincisi, kompilyator özü müəyyən edə bilər ki, obj1obj2 dəyişənlərinin tipi String-dir. İkincisi, əgər metod kodunda yalnız bir komanda varsa, əyri mötərizələr və return operatorunu da yazmaya bilərsiniz.

Qısaldılmış versiya belə olacaq:

Comparator<String> comparator = (obj1, obj2) ->
   obj1.length() - obj2.length();

Collections.sort(list, comparator);

Əgər comparator dəyişəni yerinə dərhal dəyərini yazsaq, belə bir variant alınacaq:

Collections.sort(list, (obj1, obj2) ->  obj1.length() - obj2.length() );

Nə deyirsiniz: yalnız bir sətir kod, artıq heç bir məlumat yoxdur — yalnız dəyişənlər və kod. Daha qısası yoxdur! Ya var?



5. Bu necə işləyir

Əslində, kodu daha da qısa şəkildə yazmaq olar. Amma bu barədə bir az sonra.

Lambda ifadəsini, tək bir metodlu interfeys tipi istifadə olunan yerdə yaza bilərsiniz.

Məsələn, bu kodda Collections.sort(list, (obj1, obj2) -> obj1.length() - obj2.length()); lambda ifadəsini istifadə edə bilərsiniz, çünki sort() metodunun imzası aşağıdakı kimidir:

sort(Collection<T> colls, Comparator<T> comp)

Birinci parametr kimi metod sort-a ArrayList<String> kolleksiyasını ötürdükdə, kompilyator ikinci parametrin tipini Comparator<String> olduğunu təyin edə bildi. Bundan da belə nəticə çıxardı ki, həmin interfeysin yeganə metodu int compare(String obj1, String obj2) var. Qalanı isə texnikanın işidir.

Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION