Groovy
propone molte caratteristiche interessanti, sviluppate
attorno ad una sintassi più simile ai linguaggi
di scripting che al rigoroso e preciso linguaggio Java.
Gli statunitensi identificano questo come syntax sugar:
sintassi non indispensabile, ma che consente di esprimere
più logica con meno codice.
Groovy pu essere utilizzato in alternativa al
compilatore javac per produrre bytecode, oppure per
implementare lo scripting in applicazioni Java.
Closures
Fin dai tempi del Clipper, ed anche più recentemente
con linguaggi come Python e Ruby, esisteva il concetto
del blocco di codice, che prevede la memorizzazione
di una porzione di codice all'interno di una variabile
per poterla manipolare.
Una closures di Groovy pu essere immaginata come
una classe interna anonima che hanno un solo metodo
che, e questo è il concetto nuovo, è anonimo
esso stesso. Il vantaggio delle closures è che
non richiede la dichiarazione di classi e metodi; ad
esempio, il seguente codice calcola la sommatoria di
un insieme di valori (la parola chiave it è il
valore corrente):
count = 0
[1, 2, 3, 4].each { count += it }
Un
tipico utilizzo delle closures è la sostituzione
degli iteratori, ma vengono utili anche con la gestione
dei database.
SQL
Groovy appiattisce infatti l'accesso alle basi dati
nascondendo le API JDBC dietro una sintassi che permette
l'accesso ai record ed alle colonne con una sintassi
simile a quella di Expression Language (tecnologia JSP).
Nell'esempio seguente, viene eseguita una query e creata
una closure con i dati risultanti; per accedere alla
colonna name viene utilizzata la sintassi it.name:
import
groovy.sql.Sql
import groovy.sql.TestHelper
foo
= 'cheese'
sql = TestHelper.makeSql()
sql.eachRow("select
* from FOOD where type=${foo}") {
println "Gromit likes ${it.name}"
}
Markup
Un'altra caratteristica interessante è il supporto
ai linguaggi di markup come XML, HTML, SAX, W3C DOM,
Ant, ma anche interfacce Swing. La cosa interessante
è che, indipendentemente dal tipo di dato che
si sta costruendo, la sintassi è uguale, ad esempio,
il seguente codice esegue una query sul database e costruisce
un flusso XML con i dati ottenuti:
import
groovy.sql.Sql
import groovy.sql.TestHelper
import groovy.xml.MarkupBuilder
sql
= TestHelper.makeSql()
xml = new MarkupBuilder()
ignore
= 'James'
sql.queryEach ("select * from person where firstname
!= $${ignore}") {
person | xml.customer(
id:person.id, type:'Customer',
name:person.firstname + " " + person.lastname)
}
Il
programma genera un output simile:
<customers>
<customer id="123" type="Customer"
foo="whatever">
<role>partner</role>
<name>James</name>
<location id="5" name="London"/>
</customer>
</customers>
La
tipologia di dato costruita è identificata dal
builder (p.e. DOMBuilder, SAXBuilder, MarkupBuilder,
AntBuilder, SwingBuilder); in funzione del tipo utilizzato
si otterrà un risultato differente.
Collezioni
Un argomento caro ai linguaggi di scripting è
per il supporto alle collezioni, del tipo mappe
o liste. Groovy consente di generare dinamicamente liste
utilizzando le parentesi quadre:
list = [1, 2, 'hello', new java.util.Date()]
assert list.size() == 4
assert list.get(2) == 'hello'
Le
mappe hanno un approccio simile, ma richiedono di specificare
il valore della chiave da associare a ciascun valore,
elemento che si indica utilizzando i due punti (:):
map = ['name':'James', 'location':'London']
assert map.size() == 2
assert map.get('name') == 'James'
L'iterazione
all'interno di una lista è possibile attraverso
la parola chiave for, che assomiglia molto alla nuova
for di Java 1.5:
list
= [1, 2, 3]
for (i in list) { println i }
Javabean
più facili
Un'altra area dove Groovy semplifica il lavoro del programmatore
è quella dei Javabean che possono essere specificati
in modo pià rapido, in particolare omettendo
i getter ed i setter che in molte implementazioni non
fanno niente di più che memorizzare e restituire
il valore delle proprietà. Per questo motivo
il tipico oggetto Customer assume questa forma:
import
java.util.Date
class
Customer {
// properties
Integer id
String name
Date dob
// sample code
static void main(args) {
customer = new Customer(id:1,
name:"Gromit", dob:new Date())
println("Hello ${customer.name}")
}
}
Un'altro
elemento salta subito all'occhio: non è necessario
un costruttore che salvi ciascun valore passato come
parametro, ma i valori delle proprietà possono
essere passati con la sintassi utilizzata per le mappe.
Groovy appiattisce dunque Javabean e strutture dati
standard.
Questa sintassi non è vincolante, in quanto è
possibile utilizzare quella classica di Java; nell'esempio
seguente sono mostrate una proprietà in read
only ed una con setter protetto. Queste caratteristiche
si ottengono con i normali modificatori di visibilità
di Java.
class
Foo {
// read only
private String name
public String getName() { return name }
// read only property con setter protetto
Integer amount
protected void setAmount(Integer amount)
{ this.amount = amount }
}
Sono
inoltre supportate proprietà con tipo dinamico,
che quindi possono ospitare riferimenti a tipi di dati
non noti in fase di sviluppo.
File
ed I/O
Un altro punto di similitudine con altri linguaggi di
scripting è l'accesso facilitato ai file di testo;
ad esempio, per produrre in output un file si pu
scrivere:
import java.io.File
new File("foo.txt").eachLine { line | System.out.println(line)
}
Se
il codice eseguito da eachLine() solleva una eccezione,
è responsabilità di Groovy rilasciare
tutte le risorse allocate dall'apertura del file (come
chiudere il file stesso).
Anche l'accesso ai processi è molto semplice
e nasconde del tutto l'utilizzo delle pipe:
process = "ls -l".execute()
println "Found text ${process.text}"
Per
realizzare queste funzionalità, Groovy implementa
modifiche alla libreria di base di Java. Ad esempio,
BufferedReader guadagna la nuova getText(), BufferedWriter
ottiene writeLine(), InputStream acquista eachLine(),
readLines(), withReader(), withStream(). E questi sono
solo esempi.
Conclusioni
Altre caratteristiche includono il supporto alle espressioni
regolari tipo Perl, un nuovo linguaggio per i percorsi
(come XPath o Jexel), il supporto ad Ant ed un sistema
di template. Ulteriori moduli, in fase di sviluppo,
includono un ponte con SWT ed il supporto ai Web Services
con XML-RPC.
Per gli amanti degli IDE, sono disponibili anche plug-in
per Eclipse, IntelliJ e JEdit, anche se il supporto
è ancora basilare.
|