Skip to end of metadata
Go to start of metadata

A Java8 – jobban mondva a Lambda csomag – lehetőséget ad arra, hogy interfészekbe lehessen tenni kódrészleteket, amelyeknek első nekifutásra nem sok értelme van, hiszen erre eddig is lehetőséget kaptunk az absztrakt osztályokon keresztül... a többszörös öröklődésre pedig nincs akkora igény, hogy komolyan el kellene gondolkodni rajta a nyelvet módosító fejlesztőknek. Ha jobban beleássuk magunkat a Lambda rejtelmeibe, akkor láthatunk egy logikus folyamatot, amely megmagyarázza a Virtual Extension Method néven nevezett nyelvi eszköz szükségességét. Írjunk egy rövid programot, amely létrehoz egy listát, benne számokkal 0 és 9 között:

LambdaRun.java
public class LambdaRun
{

  public static void main(String[] args)
  {
    java.util.List<Integer> numbers =
        new java.util.ArrayList<Integer>(java.util.Arrays.asList(new Integer[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}));
  }
}

A feladat legyen egyszerű: írassuk ki a listában található számokat... a hagyományos módszer szerint valami ilyesmit írnánk a program végére:

Hagyományos módszer
for(Integer number : numbers) System.out.println(number);

Az új módszer se sokkal kevesebb, a List interfész kapott egy új – forEach nevű – metódust, amelybe tudunk írni Lambda kifejezéseket:

Lambda módszer
numbers.forEach(number -> {System.out.println(number);});

Az ördög a részletekben rejlik, nézzünk bele a List interfész forráskódjába, de ott nem találunk benne forEach metódust, amelyet a Collection interfészben se találunk (amelyből a List származik), mivel ez a metódus az Iterable interfészben van, amely a Collection egyik őse, de lássuk gyorsan az alapértelmezett metódust, amelyben egy delegate metódustörzs szerepel:

Iterable.java
void forEach(Block<? super T> block) default {
    Iterables.forEach(this, block);
}

Ha tovább nyomozunk, akkor megtaláljuk a konkrét implementációt az Iterables osztályban, amely tulajdonképpen végrehajtja a Lambda blokkot:

Iterables.java
public static <T> Iterable<T> forEach(final Iterable<? extends T> iterable, final Block<? super T> block) {
    Objects.requireNonNull(iterable);
    Objects.requireNonNull(block);
    for (T each : iterable) {
        block.apply(each);
    }

    return (Iterable<T>) iterable;
}

Kerekedik a dolog... ezért kell a default metódustörzs az interfészekbe, mert a Lambda expression miatt az összes alapvető interfészbe fel kell venni a fentihez hasonló új metódusokat, amelyeknek működnie kell a régi implementációkkal – hiszen a platform alapvető interfészeit sok helyen sokszor implementáltuk saját osztályokban! Csak úgy lehet ezt megoldani, ha az interfészekben lehetőség van olyan metódusokat felvenni, amelyeket nem kell implementálni, a kialakult megoldás pedig a platform egészében használható eszköz lesz... csak szoknunk és tanulnunk kell még ezt a megoldást.

      
      
Page viewed times

18 Comments

  1. Anonymous

    Erdekes ez a lambda dolog. Bar ugy gondolom, hogy ezt is meg lehetett volna oldani sima callback fuggvennyel, szoval leginkabb csak azert csinaltak, hogy elmondhassak, hogy java-ban is van Lambda.

    Foleg, mert a fenti peldaban a lamba modszer 1 karakterrel sem rovidebb mint a hagyomanyos modszer...

    1. Auth Gábor AUTHOR

      Erdekes ez a lambda dolog. Bar ugy gondolom, hogy ezt is meg lehetett volna oldani sima callback fuggvennyel, szoval leginkabb csak azert csinaltak, hogy elmondhassak, hogy java-ban is van Lambda.

      Érdekesnek érdekes... egyelőre nem tudom hova tenni, hogy lesz ilyen a Java nyelvben. A callback függvény is működne, de ahhoz kellene egy metódus, ami okán már kesze-kusza lesz a kód. Mondjuk így is meg kell szokni, mert nem áll rá a szemem ezekre a kis beágyazott izékre... (smile)

      Foleg, mert a fenti peldaban a lamba modszer 1 karakterrel sem rovidebb mint a hagyomanyos modszer...

      Nyilván a példa kicsit erőltetett és lehetne találni egy csomó olyan példát, amely rövidebb és átláthatóbb kódot eredményez, de most még azt mondja a belső hang, hogy a "változás rossz!" (smile)

    2. Zs

      Azért ha callback függvénnyel csinálnád, akkor valami ilyesmit irnál, hogy:

      numbers.forEach(new Callable<Integer>(){ public void call(Integer number) {System.out.println(number);});

      ennél azért jobb ez lambda kifejezés.

      1. Anonymous

        Ez igaz. Viszont ebben nincs semmi "magical", minden ott van a kodban. Barki, aki tud java-ul, az erti.

        Ugy erzem, hogy ezzel a lambda dologgal a funkcionalis megkozelitest probaljak eroltetni, de (egyelore) nem erzem ugy, hogy a java (szeru) nyelvekben ez olyan pozitivum lenne.

  2. Ha használtál valaha C# ot, akkor nagyon hamar elkezded hiányolni a JAVAból. 

    Ezt már nagyon régen bele kellett volna tenni, de valszeg akkor ma sem lenne még kint a Java 7.

    1. Auth Gábor AUTHOR

      Én alapvetően szerver oldalon dolgozom, és nem nagyon tudom elképzelni, hogy mire tudnám értelmesen használni... de biztos bennem van a hiba... (smile)

      1. Ez egy pici C# kód, ahol kiszűrtem a súlynál null elemeket tartozóakat, majd rendeztem elsődlegesen a súly szerint, az azonos súlyúakat név szerint. Nem szép minta és pontatlan is ( (smile) ), de a lényege, hogy három sorban sikerült ezt a célt elérni. Java8-tól ez is működni fog.

         

        var myLittleList = new List<MyElement>();

        myLittleList.AddRange(_myBigList.Where(e => e.myWeight != null));

        myLittleList.Sort((m1, m2) => (m2.myProperty.CompareTo(m1.myWeight)*100+m1.name.CompareTo(m2.name)));

        1. Auth Gábor AUTHOR

          A lista honnan jön? Ha adatforrásból (és nyilván adatforrásból), akkor ezt már ott meg tudom csinálni...

          1. Anonymous

            johet a kliens oldalrol felhasznaloi imputbol is, ahol nem hiba, ha kitorlik a suly erteket a mezobol, tehat nem validalhatsz ilyet (wink)

            1. Anonymous

              Boobek voltam

            2. Auth Gábor AUTHOR

              Akkor meg a JS szűri ki... (smile)

              Értem én, hogy ez egy must have desktop feature, de a Java nem volt és már nem lesz soha desktop platform, Android-on a GUI megoldja a validációt, a service rétegnek meg ott a SQLite.

               

              Ezt már nagyon régen bele kellett volna tenni

              Alapvetően erre reagáltam.

          2. Mondok én is egy példát: mondjuk a súly helyett az utolsó havi fizetés szerepel. A listában pedig az idén a cégnél dolgozók szerepelnek, de mondjuk néhányan már távoztak a cégtől, és azoknak nincs fizetésük.

            Tény, hogy le lehet kérni adatforrásból, de minek, ha ebben a második listában már megkaptuk, amit szerettünk volna.

            Boobek altarnatívája is egy lehetséges út.

            1. Auth Gábor AUTHOR

              Tény, hogy le lehet kérni adatforrásból, de minek, ha ebben a második listában már megkaptuk, amit szerettünk volna.

              Tehát ismét a kliens oldalon csinálunk valamit az adatokkal valamilyen esemény hatására (például táblázat rendezése, szűrése)... (smile)

              C# van kliens oldalon, ott van értelme. Java elenyésző van kliens oldalon, és nem mernéd szerintem kijelenteni, hogy csak és kizárólag azért nincs, mert hiányzik a nyelvből a lambda expression és néhány más dolog, ami C# esetén rendelkezésre áll.

              Alapvetően attól tartok, hogy a lambda expression és a LINQ agyatlan használata is átszivárog, amikor az adatbázistól elkér az ember mindent, de tényleg mindent, leutaztatja a kliensre és ott ezekkel az eszközökkel keresgél benne, aztán csodálkozik, hogy ami működött 100 rekordra, az nem megy százmillió rekorddal. Nem egy példát láttam erre sajnos.

              A szűrést és a rendezést csinálja az adatforrás, a service réteg oldja meg a cache funkciókat, a kliens csak mutassa meg, amit kell... szerintem... (smile)

      2. Zs

        Nem értem mi a köze a szerver/kliens oldalnak egy nyelvi ficsőrhöz ? a for ciklust hol szoktad csak használni? (smile)

        1. Auth Gábor AUTHOR

          Errefelé nem szokás a teljes adathalmazt letolni a kliensnek, hogy majd ott kiválogatja, ami neki kell... (smile)

          Nem vagyok konzervatív, szeretem az új dolgokat, de szerintem ez a lambda expression kissé túl van lihegve.

          1. Zs

            Tehát Te mindig olyan pontos SQL lekérdezéseket irsz, hogy a visszakapott eredményen már semmi módositásra, csoportositásra, rendezésra, összekapcsolásra nincs szükség, csak elkészited a List<MyOrderLineResult> objektumodat a ResultSet-edből, és azt már egy az egyben el lehet küldeni a kliensnek ? (smile)

            Ez a legegyszerűbb esetekben még hihető is, de én inkább eddig azt láttam, hogy van egy objektum model, ami az adatbázisból jön, s abból készülnek el a DTO-k, néha nem triviális adat masszirozással.

             Én a kevesebb (érthető) kód, kevesebb hiba, mantrában hiszek. Nyilván az érthetőség fontos szempont, ha valaki látott már K-t (smile)

             

            1. Auth Gábor AUTHOR

              Ott igyekszem megoldani az adatok szűrését, ahol a leginkább célszerű. Az esetek igen nagy részében ez az adatbázis. Ha utólag rendezni kell, akkor arra is teljesen kész megoldások vannak, nem feltétlen egy lambda expression hiányzik a boldogsághoz. Majd meglátjuk néhány év múlva.

              1. Zs

                Nyilván, ahol a legcélszerűbb, ott lehet használni lambdákat, függetlenül, hogy az valamilyen kontextusban "szerver" vagy "kliens" oldalinak számít. Többnyire tömörít a kódon, szvsz.