Van két fontos különbség a Java és a Groovy között, amit mindenképpen megosztanék ezen a ponton. Groovyban nincsenek primitív típusok, még ha látszólag úgy is deklarálunk egy változót, az eredmény mindig egy példány lesz a memóriában. A másik, hogy a dupla egyenlőség vizsgálat, Javatól eltérően érték szerint hasonlít össze!
Minden Java fejlesztő rémálma a NullPointerException, éppen ezért Javaban a műveletek nagy részét megelőzi erre vonatkozó ellenőrzés, ami csak átláthatatlanabbá teszik a kódot. Groovyban ez a teljes vizsgálat elvégezhető egyetlen kérdőjel segítségével:
1 | int foo = bar?.length ? bar.length : - 1 ; |
Következő hasznos egyszerűsítés amit meg szeretnék említeni az un. Elvis operátort.
1 | int foo = bar ?: - 1 ; |
Soron következő kedvencem a GString. Stringek összefűzésének problémájával a legtöbben már egészen biztos találkoztunk. Kis mennyiségű szöveg összefűzésénél még nem is akkora a probléma, mert az egy sorban elvégzett String összefűzés automatikusan egy StringBulder osztályra fordul. Nagyobb mennyiség esetén (hallottam olyan helyről, ahol a mai napig 80 karakter sorhossz) macerássá válik a művelet. A Groovy eszköztárában egy az Expression Language-re kísértetiesen hasonlító megoldást építettek.
1 2 | String foo = "Foo" String bar = "${foo} Bar" |
1 2 3 4 | def sql = "" " select * from ${table} where bar = ${foo} "" " |
Reguláris kifejezések használatát is lényegesen leegyszerűsítették a Groovys srácok.
1 2 3 | Pattern pattern = ~/(.*)/ boolean find = 'foo' ==~ pattern Matcher m = 'foo' =~ pattern |
Mint ahogy a bevezetőben említettem, Groovyban nincsenek primitív típusok, most lássuk, hogy ennek miért is van jelentősége. A fordító bizonyos operátorokat automatikusan átfordítja az objektum metódus hívásaira.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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++ o r ++a // a.next() a−− o r −−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) ~a // a.bitwiseNegate() −a // a.negative() +a // a.positive() a <=> b : a.compareTo(b) |
1 2 3 4 5 | def today = new Date() def tomorrow = today + 1 def yesterday = today - 1 assert today.plus( 1 ) == tomorrow assert tomorrow.minus( 1 ) == today |
1 | StringBuilder sb = 'bar' << 'foo' |
A következő érdekesség amire szeretném felhívni a figyelmet a Groovy osztálykezelése. A Groovy egy speciális osztályon keresztűl hozzáférést biztosít az osztályokhoz, és lehetőséget ad azok bővítésére.
1 2 3 4 | String.metaClass.prefixFirstLette = { prefix -> return "${prefix}_${delegate.substring(0, 1)}" } println '<span style="background-color: white;">bar' </span><span style= "background-color: white;" >.prefixFirstLette( 'foo' );</span> |
Az előző példában egy újabb speciális Groovy osztállyal találkozhattunk, a Closure-val, mely osztály kiemelten fontos a nyelv szempontjából, és számtalan metódusnak átadható paraméterként.
1 2 3 4 | Closure c = { i -> return i } println c.call( 1 ) |
Következő témakör, amelyet fontos kihangsúlyozni a Groovyval kapcsolatban, hogy natív támogatást nyújt listák és mapok kezelésére, ráadásul számos olyan funkcióval egészítették ki ezen osztályokat, amik megkönnyítik a velük végzett műveleteket. Pár példa a teljesség igénye nélkül:
1 2 3 4 5 6 7 8 | def words = [ 'ant' , 'buffalo' , 'cat' , 'dinosaur' ] assert words.findAll{ w -> w.size() > 4 } == [ 'buffalo' , 'dinosaur' ] assert words.collect{ it[ 0 ] } == [ 'a' , 'b' , 'c' , 'd' ] def list = [[ 1 , 0 ], [ 0 , 1 , 2 ]].sort { item -> item.size() } assert list == [ [ 1 , 0 ], [ 0 , 1 , 2 ] ] assert [ 1 , 3 , 5 ] == [ 'a' , 'few' , 'words' ]*.size() //minden elemen végrehajtja a size() metódust |
1 2 3 | def greeting = 'Hello Groovy!' assert greeting[ 6 .. 11 ] == 'Groovy' assert greeting[ 0 , 2 , 4 ] == 'Hlo' |
A következő érdekesség az XML kezelés Groovyban. Okulva a Java hiányosságából, szintén natív támogatás van XML struktúrák kezelésére.
1 2 3 4 5 6 7 8 9 | def builder = new groovy.xml.MarkupBuilder() builder.book { author 'Bar Foo' title 'sometitle' properties { pages 42 } } println builder |
1 2 3 4 5 6 7 | < book > < author >Bar Foo</ author > < title >sometitle</ title > < properties > < pages >42</ pages > </ properties > </ book > |
1 2 3 4 5 | def address = 'http://jpattern.blogspot.com/favicon.ico' def file = new FileOutputStream(address.tokenize( "/" )[- 1 ]) def out = new BufferedOutputStream(file) out << new URL(address).openStream() out.close() |
Utoljára hagytam a legkevésbé fontos, de talán mégis hasznos újítást az importok területén. Lehetőség van Groovyban importált osztály-t aliasszal megjelelölni.
1 2 3 | import org.springframework.context.i18n.LocaleContextHolder as LCH ... def locale = LCH.getLocale() |
A pozitívumok után következzenek a negatívumok, bár személy szerint nem sok ilyet találtam. Az első, hogy a Groovy nem támogatja belső osztályok definiálását, ami szerintem a Java eszköztárának egy fontos kelléke. A Másik, hogy dinamikus típusú nyelv lévén az IDE támogatás meg sem közelíti a Javaét. Bár mindhárom elterjedt IDE (Netbeans, Eclipse, IntelliJ) rendelkezik Groovy támogatással, Javahoz szokott fejlesztőként számtalan kényelmi funkciót kell nélkülözni.
Véleményem szerint egy elég erőteljes nyelv lett a Groovy, a fejlesztők igyekeztek a Java hiányosságaiból tanulni, miközben megőrizték a Javaban rejlő erőt teljes mértékben. Bár mindenki azt csinál amit akar, én személy szerint alapos Java ismeretek nélkül nem ajánlom a nyelvet kezdőknek, ugyanis ahhoz elég sok dologban tér el a Javatól, hogy rossz szokásokat fejlesszen későbbi Java programozáshoz. Ilyen pl. a dupla egyenlőség vizsgálat, a String automatikus StringBuilderré alakítása bizonyos operátorok használatakor, A streamek kezelése, stb. Remélem további ismerkedésre inspirál mindenkit ez a kis írás, és sokan kiegészítik ezzel a remek eszközzel programozói repertoárjukat.