Java-hoz képest eltérések:
Ugyan azok a kulcsszavak, mint Java-ban.
+Az 'in' is kulcsszó.
A kódban bárhol lehet változókat deklarálni. Ezt a def kulcsszóval tehetjük meg. Ilyenkor dinamikusan rendelődik típus a névhez, ami változhat új definíciónál.
Groovyban a Java-val ellentétben az operátorok viselkedése testreszabható, megváltoztatható.
Aritmetikai operátorok:
a + b a.plus(b)
a - b a.minus(b)
a * b a.multiply(b)
a ** b a.power(b)
a / b a.div(b)
a % b a.mod(b)
a | b a.or(b)
a & b a.and(b)
a ^ b a.xor(b)
a++ or ++a a.next()
a-- or --a a.previous()
a[b] a.getAt(b)
a[b] = c a.putAt(b, c)
a << b a.leftShift(b)
a >> b a.rightShift(b)
switch(a) { case(b) : } b.isCase(a)
~a a.bitwiseNegate()
-a a.negative()
+a a.positive()
Logikai operátorok:
a == b a.equals(b) or a.compareTo(b) == 0
a != b ! a.equals(b)
a <=> b a.compareTo(b)
a > b a.compareTo(b) > 0
a >= b a.compareTo(b) >= 0
a < b a.compareTo(b) < 0
a <= b a.compareTo(b) <= 0
Nem érzékenyek a null-okra, azaz ha az operandus null, a kiértékelés nem dob NullPointerException-t.
Gyűjtemények operátorai:
'spread' operátor: segítségével egy összetett objektum minden elemén végrehajtható egy művelet.
Objektumokhoz kapcsolódó operátorok:
'.': (pont) operátor: tagfüggvény hívására, adattagok/propertyk elérésére használható.
'.&': referencia operátor
'as': típus kényszerítés
'==': a java-s equals(), érték szerinti egyenlőséget vizsgál. Objektumok azonosságára használható az 'is' operátor.
'instanceof': mint Java-ban. Megadja, hogy az objektum az adott típusú-e.
További operátorok:
'getAt()'/satAt()': iteratív adatszerkezeteknél adott pozíción lévő adat lekérése, beállítása.
tartomány operátor '(..)'
Elvis operator '?:': akkor használható, ha hamis vagy null értéknél szeretnék használható információt visszaadni pl.:
A java kódban lehetséges annotálást használni, természetesen erre lehetőség nyílt Groovyban is. A következőkben pár annotáció kerül bemutatásra, olyan annotációk amlyek a groovyra jellemzőek.
A Groovy 2.0 óta lehetőség nyílt típus ellenőrzésre. Ez egy opcionális lehetőség, amit a @TypeChecked annotációval érhetünk el. Hasonlóan mint Javaban itt is annotálhatjuk az adattagjainkat. Ha használjuk kódunkban az annotációt, akkor a fordító sokkal részletesebben közli a felmerült hibákat és kivételt is dobhat, olyan esetekben amikor például elgépeltünk valamit a kódban vagy olyan metódust próbálunk meghívni, ami nem található. Ez amiatt van, mert a Groovy egy dinamikus nyelv, futási időben értékeli ki a típusokat. Vannak olyan esetek amelyekben ez előny, például a következő kódrészletben:
Az html tagek száma csak futási időben derül ki, ezért a metódusok még nem léteznek a fordítási időben, így egy típus ellenőrzés hátrányt jelentene ebben az ezetben a fejlesztő számára, hiszen korlátozva lenne egy ismeretlen html kód dinamikus feldolgozásában.
Mikor használjuk a típus ellenőrzést és hogyan tegyük?
Vannak esetek amikor szükségünk van ilyen megszorításra, ami biztonságosabbá teszi a kódunkat.A következő példában a foo metóduson típusát ellnőrzésre kerül a myextension.groovy fáljban található típus ellnőrzési szabályok alapján.
A DSL megengedi hogy megakaszuk a forditási folyamatot, sőt típus ellenőrzési kifejezéseket használjunk ’event-driven’ segítségével. Például a mikor a típus ellenörző belépe egy metódus törzsébe akkor kivált egy beforeVisitMethod eseményt, amelyre a következő képpen lehet reagálni a típus ellenőrző fájlban:
A következő példában van egy robot objektumunk amit szeretnénk elöre mozgatni 100 métert.Ha például a Robot osztály kódja ez:
akkor a szkriptünket a következő féleképpen tudjuk típus ellenőríztetni:
Ebben az ezetben fordítási időben a robot változó nincs deklarálva hibát kapjuk. De ha a következő képpen átalakítjuk a kódot, akkor nem jön ebben az esetben hiba.
Ha a myextension.groovy tartalma a következő kód.
A kód a robot változó esetén meghatározza a szkript, hogy az egy Robot típus.
A meta annotációk olyan annotációk, amelyek fordítási időben más annotációkra cserélődnek ki. Egy meta annotáció kicserélődhet egy vagy akár több más annotációra is. A meta annotációk által jelentősen csökkenthetjük az olyan programkód méretét amelyben számos annotáció szerepel.
Mikor és hogyan használjuk?
Kezdjük egy egyszerű példával. Tegyük fel, hogy van két általunk definiált annotáció. Az egyiket úgy hívják, hogy @Transactional a másikat pedig úgy, hogy @Service. Szeretnénk az osztályunkat ellátni mindkét annotációval. Ezt a következőképpen tehetjük meg:
A meta annotáció segítségével ezt a két annotációt kicserélhetjük egyetlen annotációra. Ezt a következőképpen tehetjük meg: először is egy aliast kell definiálnunk a következő módon:
A létrehozott @TransactionalService annotáció egy meta annotáció, amely egybefoglalja számunkra a két annotációnkat. Ezt a működést úgy érjük el, hogy az interfészt annotáljuk @AnnotationCollector-ral.
Működés
Mielőtt továbbmegyünk, néhány szó a működésről: először is, a Groovy-ban lehetőség van használni már lefordított, vagy a forrásban jelen levő meta annotációkat is.
Tehát a használt meta annotáció lehet korábban lefordított (máshonnan importált), vagy az adott forrásban definiált. Fontos ezenkívül, hogy a meta annotáció egy kizárólag a Groovy-ban használható konstrukció. Ez azt jelenti, hogy egy Java osztályhoz nem lehet (egy Groovy-ban megírt) meta annotációt használni, és ugyanígy Java-ban nem lehet meta annotációt írni - mind a meta annotáció definíciója és a felhasználása Groovy-ban kell, hogy történjen.
Amikor a Groovy fordító egy meta annotációt talál, akkor a programkódban kicseréli azt az általa egybefoglalt annotációkkal. Tehát az előző példánkat véve: a fordító a @TransactionalService meta annotáció helyére a @Transactional és a @Service annotációkat illeszti. Ez a lépés a szemantikus analízis során történik.
Meta annotáció paraméterek
Az annotációk egybefogásán túl a meta annotációk használhatók a tartalmazott annotációkkal kapcsolatos műveletekre is, ideértve a hozzájuk tartozó paraméterek feldolgozását.
A következő példában két annotációnk van, mindkettő egy-egy paraméterrel:
Ezeket szeretnénk egy meta annotációval helyettesíteni, @Explosive néven:
Ezután amikor az @Explosive-ot a korábbi két annotáció helyett használjuk, az azokban definiált értékeket fogja a meta annotáció is tartalmazni.
Azonban ezek az értékek felülírhatók
Ekkor a megadott értékkel felülírjuk a korábban a @Timeout-ban definiált értéket.
Névütközések
Névütközésről ebben az esetben akkor van szó, ha két vagy több annotációban ugyanazzal a névvel definiálunk paramétert. Ebben az esetben, ha az őket összefogó meta annotációban értéket adunk ennek a "közös" paraméternek, akkor az az érték az összes lehetséges helyre bemásolódik, felülírva mindegyiket.
Például a következő kódrészlet:
a következő eredményt adná:
Mint láthatjuk, a második esetben (amikor meta annotációt használtunk, annak paramétert adva) a megadott érték mindkét annotációba bemásolódott.
Abban az esetben, ha ugyan a paraméterek neve ugyanaz, de a típusuk különböző, fordítási hibát kapunk. Azonban ennek a problémának a kiküszöbölésére lehetőség van az úgynevezett feldolgozót használni.
Saját annotáció feldolgozók
A saját annotáció feldolgozó segítségével a programozó tetszőlegesen befolyásolni tudja az annotáció működését. Példaként nézzük meg, hogyan van a @CompileDynamic implementálva a Groovy 2.1.0-ban. A @CompileDynamic egy meta annotáció, amely kicserélődik @CompileStatic(TypeCheckingMode.SKIP)-re. A meta annotáció feldolgozó azonban nem tartalmaz enum-okat, ezért azt nekünk kell előállítanunk.
Ezért ahelyett, hogy ezt írnánk:
A meta annotációt inkább így fogjuk definiálni:
A legszembetűnőbb változás, hogy az interfészünk már nincs a @CompileStatic-kal annotálva. Ehelyett a 'processor' paramétert használjuk. Ez egy olyan osztályra hivatkozik, amely legenerálja az annotációt.
Ez az osztály a következőképpen néz ki
Ez a saját feldolgozó az alapértelmezett feldolgozóból származik és felüldefiniálja a 'visit' metódust. Ez a metódus azon annotációk listájával tér vissza, amelyek az absztrakt szintaxisfában (AST) a meta annotáció helyére fognak kerülni. Tehát a metódus feladata mindössze annyi, hogy legenerálja a megfelelő AnnotationNode elemet. Természetesen lehetséges az ősosztályra is támaszkodni a működés során, például a paraméterek feldolgozásában.