1. Mga Interface

Upang maunawaan kung ano ang mga function ng lambda, kailangan mo munang maunawaan kung ano ang mga interface. Kaya, alalahanin natin ang mga pangunahing punto.

Ang interface ay isang pagkakaiba-iba ng konsepto ng isang klase. Sabihin nating isang klaseng naputol nang husto. Hindi tulad ng isang klase, ang isang interface ay hindi maaaring magkaroon ng sarili nitong mga variable (maliban sa mga static). Hindi ka rin makakalikha ng mga bagay na ang uri ay isang interface:

  • Hindi ka maaaring magdeklara ng mga variable ng klase
  • Hindi ka makakalikha ng mga bagay

Halimbawa:

interface Runnable
{
   void run();
}
Halimbawa ng isang karaniwang interface

Gamit ang isang interface

Kaya bakit kailangan ng isang interface? Ang mga interface ay ginagamit lamang kasama ng mana. Ang parehong interface ay maaaring mamana ng iba't ibang klase, o gaya ng sinasabi rin — ipinapatupad ng mga klase ang interface .

Kung ang isang klase ay nagpapatupad ng isang interface, dapat itong ipatupad ang mga pamamaraan na ipinahayag ng ngunit hindi ipinatupad ng interface. Halimbawa:

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("Today: " + date.getDayOfWeek());
   }
}

TimerIpinapatupad ng klase ang Runnableinterface, kaya dapat nitong ideklara sa loob mismo ang lahat ng mga pamamaraan na nasa Runnableinterface at ipatupad ang mga ito, ibig sabihin, magsulat ng code sa isang katawan ng pamamaraan. Ganun din sa Calendarklase.

Ngunit ngayon Runnableang mga variable ay maaaring mag-imbak ng mga sanggunian sa mga bagay na nagpapatupad ng Runnableinterface.

Halimbawa:

Code Tandaan
Timer timer = new Timer();
timer.run();

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

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

Ang run()pamamaraan sa Timerklase ay tatawagin


Ang run()pamamaraan sa Timerklase ay tatawagin


Ang run()pamamaraan sa Calendarklase ay tatawagin

Maaari kang palaging magtalaga ng isang object reference sa isang variable ng anumang uri, hangga't ang uri na iyon ay isa sa mga ancestor class ng object. Para sa Timerat Calendarmga klase, mayroong dalawang ganitong uri: Objectat Runnable.

Kung magtatalaga ka ng object reference sa isang Objectvariable, maaari mo lamang tawagan ang mga pamamaraan na idineklara sa Objectklase. At kung magtatalaga ka ng isang object reference sa isang Runnablevariable, maaari mong tawagan ang mga pamamaraan ng Runnableuri.

Halimbawa 2:

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

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

Ang code na ito ay gagana, dahil ang Timerat Calendarmga bagay ay nagpapatakbo ng mga pamamaraan na gumagana nang mahusay. Kaya, ang pagtawag sa kanila ay hindi isang problema. Kung nagdagdag lang kami ng run() na pamamaraan sa parehong klase, hindi namin sila matatawag sa ganoong simpleng paraan.

Karaniwan, ang Runnableinterface ay ginagamit lamang bilang isang lugar upang ilagay ang run method.



2. Pag-uuri

Lumipat tayo sa isang bagay na mas praktikal. Halimbawa, tingnan natin ang pag-uuri ng mga string.

Upang pag-uri-uriin ang isang koleksyon ng mga string ayon sa alpabeto, ang Java ay may isang mahusay na pamamaraan na tinatawagCollections.sort(collection);

Ang static na paraan na ito ay nag-uuri sa naipasa na koleksyon. At sa proseso ng pag-uuri, nagsasagawa ito ng pairwise na paghahambing ng mga elemento nito upang maunawaan kung dapat bang palitan ang mga elemento.

Sa panahon ng pag-uuri, ang mga paghahambing na ito ay isinasagawa gamit ang compareTo() na pamamaraan, na ang lahat ng karaniwang mga klase ay mayroong: Integer, String, ...

Ang compareTo() method ng Integer class ay naghahambing sa mga value ng dalawang numero, habang ang compareTo() method ng String class ay tumitingin sa alphabetical order ng mga string.

Kaya ang isang koleksyon ng mga numero ay pagbubukud-bukod sa pataas na pagkakasunud-sunod, habang ang isang koleksyon ng mga string ay pag-uuri-uriin ayon sa alpabeto.

Mga alternatibong algorithm ng pag-uuri

Ngunit paano kung gusto nating pagbukud-bukurin ang mga string hindi ayon sa alpabeto, ngunit ayon sa haba ng mga ito? At paano kung gusto nating ayusin ang mga numero sa pababang pagkakasunud-sunod? Ano ang gagawin mo sa kasong ito?

Upang mahawakan ang mga ganitong sitwasyon, ang Collectionsklase ay may isa pang sort()pamamaraan na may dalawang parameter:

Collections.sort(collection, comparator);

Kung saan ang comparator ay isang espesyal na bagay na nakakaalam kung paano ihambing ang mga bagay sa isang koleksyon sa panahon ng isang operasyon ng pag-uuri . Ang terminong comparator ay nagmula sa salitang Ingles na comparator , na nagmula naman sa compare , ibig sabihin ay "to compare".

Kaya ano ang espesyal na bagay na ito?

Comparatorinterface

Well, ang lahat ng ito ay napaka-simple. Ang uri ng sort()pangalawang parameter ng pamamaraan ayComparator<T>

Kung saan ang T ay isang uri ng parameter na nagpapahiwatig ng uri ng mga elemento sa koleksyon , at Comparatorisang interface na may iisang paraanint compare(T obj1, T obj2);

Sa madaling salita, ang object ng comparator ay anumang object ng anumang klase na nagpapatupad ng interface ng Comparator. Ang interface ng Comparator ay mukhang napakasimple:

public interface Comparator<Type>
{
   public int compare(Type obj1, Type obj2);
}
Code para sa interface ng Comparator

Inihahambing ng compare()pamamaraan ang dalawang argumento na ipinasa dito.

Kung ang paraan ay nagbabalik ng negatibong numero, ibig sabihin ay obj1 < obj2. Kung ang paraan ay nagbabalik ng positibong numero, ibig sabihin ay obj1 > obj2. Kung ang pamamaraan ay nagbabalik ng 0, ibig sabihin ay obj1 == obj2.

Narito ang isang halimbawa ng isang comparator object na naghahambing ng mga string ayon sa haba ng mga ito:

public class StringLengthComparator implements Comparator<String>
{
   public int compare (String obj1, String obj2)
   {
      return obj1.length() – obj2.length();
   }
}
Code ng StringLengthComparatorklase

Upang ihambing ang mga haba ng string, ibawas lang ang isang haba mula sa isa.

Ang kumpletong code para sa isang programa na nag-uuri ng mga string ayon sa haba ay magiging ganito:

public class Solution
{
   public static void main(String[] args)
   {
      ArrayList<String> list = new ArrayList<String>();
      Collections.addAll(list, "Hello", "how's", "life?");
      Collections.sort(list, new StringLengthComparator());
   }
}

class StringLengthComparator implements Comparator<String>
{
   public int compare (String obj1, String obj2)
   {
      return obj1.length() – obj2.length();
   }
}
Pag-uuri ng mga string ayon sa haba


3. Syntactic sugar

Ano sa palagay mo, maaari bang maisulat nang mas compact ang code na ito? Karaniwan, mayroon lamang isang linya na naglalaman ng kapaki-pakinabang na impormasyon — obj1.length() - obj2.length();.

Ngunit ang code ay hindi maaaring umiral sa labas ng isang pamamaraan, kaya kinailangan naming magdagdag ng isang compare()pamamaraan, at upang maiimbak ang pamamaraan kailangan naming magdagdag ng isang bagong klase — StringLengthComparator. At kailangan din nating tukuyin ang mga uri ng mga variable... Mukhang tama ang lahat.

Ngunit may mga paraan upang gawing mas maikli ang code na ito. Mayroon kaming ilang syntactic sugar para sa iyo. Dalawang scoop!

Anonymous na panloob na klase

Maaari mong isulat ang comparator code sa loob mismo ng main()pamamaraan, at gagawin ng compiler ang natitira. Halimbawa:

public class Solution
{
    public static void main(String[] args)
    {
        ArrayList<String> list = new ArrayList<String>();
        Collections.addAll(list, "Hello", "how's", "life?");

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

        Collections.sort(list, comparator);
    }
}
Pagbukud-bukurin ang mga string ayon sa haba

Maaari kang lumikha ng isang bagay na nagpapatupad ng Comparatorinterface nang hindi tahasang lumilikha ng isang klase! Awtomatiko itong lilikhain ng compiler at bibigyan ito ng pansamantalang pangalan. Ihambing natin:

Comparator<String> comparator = new Comparator<String>()
{
    public int compare (String obj1, String obj2)
    {
        return obj1.length() – obj2.length();
    }
};
Anonymous na panloob na klase
Comparator<String> comparator = new StringLengthComparator();

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

Ang parehong kulay ay ginagamit upang ipahiwatig ang magkaparehong mga bloke ng code sa dalawang magkaibang kaso. Ang mga pagkakaiba ay medyo maliit sa pagsasanay.

Kapag nakatagpo ng compiler ang unang bloke ng code, bubuo lamang ito ng katumbas na pangalawang bloke ng code at bibigyan ang klase ng ilang random na pangalan.


4. Lambda expression sa Java

Sabihin nating nagpasya kang gumamit ng anonymous na panloob na klase sa iyong code. Sa kasong ito, magkakaroon ka ng isang bloke ng code tulad nito:

Comparator<String> comparator = new Comparator<String>()
{
    public int compare (String obj1, String obj2)
    {
        return obj1.length() – obj2.length();
    }
};
Anonymous na panloob na klase

Dito pinagsasama namin ang deklarasyon ng isang variable sa paglikha ng isang hindi kilalang klase. Ngunit mayroong isang paraan upang gawing mas maikli ang code na ito. Halimbawa, tulad nito:

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

Ang tuldok-kuwit ay kailangan dahil dito mayroon tayong hindi lamang isang implicit na deklarasyon ng klase, kundi pati na rin ang paglikha ng isang variable.

Ang notasyong tulad nito ay tinatawag na lambda expression.

Kung nakatagpo ang compiler ng notasyong tulad nito sa iyong code, bubuo lang ito ng verbose na bersyon ng code (na may hindi kilalang panloob na klase).

Tandaan na kapag isinusulat ang lambda expression, hindi lang namin inalis ang pangalan ng klase, kundi pati na rin ang pangalan ng pamamaraan.Comparator<String>int compare()

Ang compile ay walang problema sa pagtukoy ng paraan , dahil ang isang lambda expression ay maaaring isulat lamang para sa mga interface na may iisang paraan . Oo nga pala, may paraan para makayanan ang panuntunang ito, ngunit malalaman mo iyon kapag nagsimula kang mag-aral ng OOP nang mas malalim (pinag-uusapan natin ang tungkol sa mga default na pamamaraan).

Tingnan natin muli ang verbose na bersyon ng code, ngunit aalisin natin ang bahaging maaaring alisin kapag nagsusulat ng lambda expression:

Comparator<String> comparator = new Comparator<String>()
{
    public int compare (String obj1, String obj2)
   {
      return obj1.length() – obj2.length();
   }
};
Anonymous na panloob na klase

Parang walang importanteng inalis. Sa katunayan, kung ang Comparatorinterface ay may isang compare()paraan lamang, ganap na mababawi ng compiler ang grayed-out na code mula sa natitirang code.

Pag-uuri

Sa pamamagitan ng paraan, maaari na nating isulat ang code sa pag-uuri tulad nito:

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

O kahit ganito:

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

Agad naming pinalitan ang comparatorvariable ng value na itinalaga sa comparatorvariable.

Uri ng hinuha

Ngunit hindi lang iyon. Ang code sa mga halimbawang ito ay maaaring maisulat nang mas compact. Una, matutukoy ng compiler para sa sarili nito na ang obj1at obj2mga variable ay Strings. At pangalawa, ang curly braces at return statement ay maaari ding tanggalin kung mayroon ka lamang isang command sa method code.

Ang pinaikling bersyon ay magiging ganito:

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

Collections.sort(list, comparator);

At kung sa halip na gamitin ang comparatorvariable, agad naming ginagamit ang halaga nito, pagkatapos ay makukuha namin ang sumusunod na bersyon:

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

Well, ano sa tingin mo diyan? Isang linya lang ng code na walang labis na impormasyon — mga variable at code lang. Walang paraan upang gawin itong mas maikli! O meron?



5. Paano ito gumagana

Sa katunayan, ang code ay maaaring isulat nang mas compact. Ngunit higit pa sa na mamaya.

Maaari kang magsulat ng lambda expression kung saan gagamit ka ng isang uri ng interface na may isang paraan.

Halimbawa, sa code , maaari kang magsulat ng lambda expression dahil ang lagda ng pamamaraan ay ganito:Collections.sort(list, (obj1, obj2) -> obj1.length() - obj2.length());sort()

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

Kapag naipasa namin ang ArrayList<String>koleksyon bilang unang argumento sa paraan ng pag-uuri, natukoy ng compiler na ang uri ng pangalawang argumento ay . At mula dito, napagpasyahan na ang interface na ito ay may isang solong pamamaraan. Ang lahat ng iba pa ay isang teknikalidad.Comparator<String>int compare(String obj1, String obj2)