Groovy
Groovy je skriptovací jazyk, který běží v JVM, vychází z Javy a dokáže využívat všechny knihovny v ní napsané. Oproti staticky typované Javě je typovaný dynamicky (podporuje tedy duck typing). Navíc do samotného jazyka přidává několik vylepšení inspirovaných Pythonem, Ruby nebo Smalltalkem, které mohou zásadně zvýšit produktivitu psaní kódu za cenu vyšší runtime režie. Výkon výsledné aplikace je mnohem menší než ekvivalent napsaný v čisté Javě, což je způsobeno zmíněným dynamickým typováním, které vnitřně hojně využívá reflexi. Přesto může být použití Groovy výhodné. Když vezmeme v potaz kratší čas vývoje a možnost používat všechny Javovské knihovny, může se z Groovy stát „lepidlo“, které rychle pospojuje několik komponent.

Uzávěry
Největším tahákem Groovy jsou uzávěry neboli closures (těch se možná, ale opravdu jenom možná doškáme v Javě 7). Closure je něco jako anonymní funkce, která ovšem může přistupovat k proměnným definovaným v kontextu, jež ji obklopuje. Nemusí tedy s okolním světem komunikovat jenom přes parametry a nechová se tedy zcela jako anonymní funkce, ale spíš jako řídící struktura nebo blok kódu. Díky tomu se dá pomocí uzávěrů snadno udělat to, co by se jenom velice těžko obcházelo bez nich (například použitím anonymních tříd známých z Javy). Uzávěry by nebyly ani zdaleka tak užitečné, kdyby nebyly k mnoha objektům ze standardní Javovské knihovny (především ke kolekcím) přidány nové metody, které uzávěry využívají.
Všechno osvětlí malý příklad z Wikipedie.
Javovský kód:
for (String it : new String [] {"Rod", "Carlos", "Chris"}) { if (it.length() <= 4) { System.out.println(it); } }
ekvivalentní Groovy kód:
["Rod", "Carlos", "Chris"].findAll{ it.size() <= 4 }.each{ println it }
Metoda findAll vrátí kolekci elementů, které odpovídají podmínce z closure. Když nejsou uvedeny parametry explicitně, použije se implicitní proměnná it
. Explicitní forma closure by vypadala takto: { elem -> elem.size() <= 4 }
. Navíc metoda (pokud není deklarována jako void) automaticky vrací výsledek posledně vyhodnoceného výrazu. Proto si můžeme ušetřit mnoho zápisů return
a také proto se uvedená closure vyhodnotí, jak bychom předpokládali. Metoda each
pak iteruje nad vrácenou kolekcí. Díky tomu (a dalším novinkám, které zmíním později), prakticky odpadá nutnost psát klasické for/foreach/while cykly.
Z ukázky je pak patrná další věc a tou jsou nové literály pro kolekce. V Groovy se ArrayList vytvoří velice snadno:
def list = [1, 2, 3, "string", null, new Object()]
Asociativní pole se vytvoří také velice jednoduše:
def map = [ klic1: "Anomalocaris Detrimentum", klic2: "2084", klic3: "Cerv" ]
Klíče jsou automaticky považovány za řetězce i když kolem sebe nemají žádné uvozovky nebo apostrofy. Když chceme, aby byl klíč vyhodnocen jako proměnná, jednoduše kolem něj dáme závorky (je to sice nekonzistentní, ale na druhou stranu to reflektuje skutečnost, že v 99% případů chceme, aby klíčem byl řetězec).
operátory
Groovy do jazyka přidává některé užitečné nové operátory, které o trochu zjednoduší život.
?. Safe Navigation Operator
– je ekvivalentní s normálním tečkovým operátorem pro přístup k metodám nebo proměnným, ale když je pomocí něho volána metoda na nulové referenci, zamezí vyhození výjmky NullPointerException, ale pouze vrátí null
– s jeho pomocí je možné bezpečně volat něco takového a nestarat se nulové reference
user?.address?.steet
*. Spread Operator
– Toto je velice užitečný operátor, který nad každým prvkem kolekce provede danou operaci (volání metody, přístup k property) a výsledek vrátí v kolekci. Jde o další způsob, jak se vyhnout psaní cyklů.
parent*.action //je ekvivalentní s parent.collect{ it?.action } def names = persons*.name //vrátí kolekci jmen
Když to porovnáme s nejúspornějším řešením v Javě:
ArrayList names = new ArrayList(); for (Person p : persons) { names.add(p.getName()) }
je jasně vidět, co je stručnější.
persons*.address*.city //lze provést i vícenásobně, protože se vždycky vrátí objekt List myObjects*.toString() //na každém objketu zavolá toString() a vrátí kolekci
?: elvis operátor
– jde o kompaktnější verzí ternárního operátoru a funguje tak, že když je výraz před Elvisem vyhodnocen jako true, pak se vrátí samotný výraz, když jako false vrátí se to, co se nachází za Elvisem
def whoIsElvis = elvis ?: defrauder //ekvivalentní s def whoIsElvis = elvis ? elvis : defrauder
Regulární výrazy
Regulární výrazy byly začleněny do jazyka na syntaktické úrovni pomocí tří nových operátorů:
~string // vytvoří Pattern ze stringu string =~ pattern //hledá vzor ve stringu (find) string ==~ pattern //hledá přesnou shodu (match)
Ve spojení s uzávěrami je práce s regexy ještě snadnější a přehlednější:
def dates = [] def line = "Today is 31.01.2007, 15:01. Tomorrow is 01.02.2007, 15:01" (line =~ /(\d\d.\d\d.\d\d\d\d), (\d\d:\d\d)/).each { all, date, time -> //každý výskyt regulárního výrazu je předán jako parametr pro tuto closure dates << date }
Rozsahy
Rozsahy jsou další užitečnou vlastností Groovy. Jednoduše reprezentují rozsah hodnot od A do B.
def range1 = 2..10 //rozsah 2 až 10 def range2 = 2..<10 //rozsah 2 až 9
Rozsahy se dají použít k vytvoření podřetězců string[1..4]
nebo stejným způsobem k vytvoření podmnožin ArrayListu. Rozsah můžeme použít ve switchi:
switch (someValue) { case 1..3 : feedback = 'quite ok'; break case 3..6 : feedback = 'needs improvement'; break default: feedback = 'unknown' }
nebo v cyklu
for (i in range) { out << i }
Cykly
A tím se dostáváme k cyklům, které jsou silně inspirovány Ruby.
Cyklus můžete vytvořit úplně jednoduše:
8.times { print "průchod číslo ${it+1}" }
Nebo pomocí rozsahu:
(4..8).each { println it }
Možností je hodně a jejich kód je velice samo-popisný. Groovy dokonce klasické for-cykly nepodporuje, ale jak je vidět, nejsou třeba.
Objekty
Na rozdíl od Javy, která má primitivní typy, je v Groovy všechno objekt. Když k tomu připočteme, že použití operátoru je jenom maskované volání funkce, dostáváme možnost přetěžovat operátory. To využívá jmennou konvenci (operátor + volá metodu plus()
, – volá minus()
, << volá leftShift()
atd).
Všechny operátory jsou hojně využívány ve standardní knihovně, která je rozšířena o mnoho metod.
Např: << standardně provede připojení elementu do kolekce:
collection = [] collection << "elem" collection << 1
Dále se jako false
vyhodnocují obecně všechny objekty, které jsou považovány za prázdné, tedy prázdné kolekce, prázdné stringy, null a číslo 0.
Property
Dalším syntaktickým cukrem jsou property. Jde o zjednodušený způsob volání getterů a setterů již existujících javovských tříd.
def x = obj.someting // ekvivalentní s obj.getSomething() obj.someting = x // ekvivalentní s obj.setSomething(x)