Survey
* Your assessment is very important for improving the work of artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the work of artificial intelligence, which forms the content of this project
A Tour of Groovy
Chris Wong
cwong@makanasolutions.com
Your code in Java …
enum PeriodType { WEEKLY, MONTHLY, QUARTERLY, ANNUALLY }
@Entity
class Invoice {
@Id
int id;
@OneToMany
List<Item> items;
PeriodType periodType;
public List<Item> getFunnyItems() {
List<Item> funnyItems = new ArrayList<Item>();
for (Iterator<Item> i = items.iterator(); i.hasNext(); ) {
Item item = i.next();
if (item.isFunny())
funnyItems.add(item);
}
return items;
}
}
Your code in Groovy!
enum PeriodType { WEEKLY, MONTHLY, QUARTERLY, ANNUALLY }
@Entity
class Invoice {
@Id
int id;
@OneToMany
List<Item> items;
PeriodType periodType;
public List<Item> getFunnyItems() {
List<Item> funnyItems = new ArrayList<Item>();
for (Iterator<Item> i = items.iterator(); i.hasNext(); ) {
Item item = i.next();
if (item.isFunny())
funnyItems.add(item);
}
return items;
}
}
Hello, world
Legal code, but can omit plumbing
class Foo {
public static void main(String[] args) {
System.out.println("Hello, world");
}
}
Hello, world
Groovy also provides some shortcuts …
System.out.println("Hello, world");
Hello, world
Unnecessary punctuation just adds clutter …
System.out.println("Hello, world");
Hello, world
System.out.println('Hello, world');
Why Groovy?
The power of a dynamic language plus …
JSR 241: Java standard
Two-way contract:
a Groovy class is a Java class: it’s all bytecodes. Groovy
and Java can extend each other’s classes.
Seamless integration with Java: annotations, generics,
enums, familiar syntax.
The Groovy platform is the Java platform:
the J2SE library, debugging, profiling etc.
Spring, Hibernate, web services, TestNG
Some Groovy language features
Dynamically typed
Closures
Everything is an object. No primitives.
== means equals. Really.
Native syntax for lists, maps, regex
Operator overriding
Compact, expressive, readable
Strings
greeting = 'Hello'
println "$greeting, world"
println """
Today's date is ${new Date().toGMTString()}
Nice day, isn't it?
"""
greeting = "Hello, world"
greeting[7] == 'w'
greeting[2..4] == 'llo'
Closures
Behavior as objects
Default argument is “it”, optional.
def squareIt = { return it * it }
assert squareIt(5) == 25
10.times { println “I will not talk in class” }
Captures variables in the lexical scope
int x = 10
Closure addToX = { addThis -> x += addThis }
addToX(2)
assert x == 12
Lists and maps
mylist = [1, 2, 3, 4, 5]
// an ArrayList
assert mylist[0] == 1
mylist[2..3] = []
// deleted 3, 4
[2,3,4].collect { it * 2 } == [4, 6, 8]
[1,2,3].find { it > 1 } == 2
[1,2,3,[1,[2,3]]].flatten().unique() == [1, 2, 3]
mylist.each { doSomethingWith(it) }
mymap = [a:1, b:2, c:3] // a HashMap
mymap['a'] == mymap.a
// == mymap.get("a")
mymap['c'] = 5
// mymap.put("c", 5)
Ranges and regex
Ranges
(1..10).each { it -> println it }
switch (age) { case 15..30: … }
for (i in 1..10) { … }
'Hello, world'[2..4] == 'llo'
Regex
if ('rain' =~ /\b\w*ain\b/)
println '"rain" does rhyme with "Spain"!'
Operator overriding
Override operators by overriding methods:
a+b
a[b]
a << b
switch (a) { case b: ... }
a == b
a<b
a.plus(b)
a.getAt(b)
a.leftShift(b)
b.isCase(a)
a.equals(b)
a.compareTo(b) < 0
Groovy convenience operators
?: elvis
Java:
Groovy:
name = name != null ? name : "default"
name = name ?: "default"
?. safe dereference. No worry about nulls.
street = user?.address?.street
*. spread dot. Invoke on all items, return list.
List result = invoice.lineItems*.total()
GroovyBeans and JavaBeans
// Groovy
class MyBean {
String item
}
// Java
class MyBean {
private String item;
public String getItem() {…}
public void setItem(…) {…}
}
MyBean b =
new MyBean(item:‘foo’)
MyBean b = new MyBean();
b.setItem(“foo”);
String val = b.item
String val = b.getItem();
b.item = ‘bar’
b[‘item’] = ‘bar’
b.setItem(“bar”)
Why brevity matters: Quicksort
function sort(array) // pseudocode from Wikipedia
var list less, greater
if length(array) ≤ 1 return array
select a pivot value pivot from array
for each x in array
if x < pivot then append x to less
if x > pivot then append x to greater
return concatenate(sort(less), pivot, sort(greater))
-------------------------------------------------------def sort(list) {
// Groovy implementation
if (list.size() <= 1) return list
def pivot = list[0]
def less
= list.findAll {it < pivot}
def same
= list.findAll {it == pivot}
def greater = list.findAll {it > pivot}
sort(less) + same + sort(greater)
}
Quicksort in Java
public static void qsort(Comparable[] c,int start,int end){
if(end <= start) return;
Comparable comp = c[start];
int i = start,j = end + 1;
for(;;){
do i++; while(i<end && c[i].compareTo(comp)<0);
do j--; while(j>start && c[j].compareTo(comp)>0);
if(j <= i)
break;
Comparable tmp = c[i];
c[i] = c[j];
c[j] = tmp;
}
c[start] = c[j];
c[j] = comp;
qsort(c,start,j-1);
qsort(c,j+1,end);
}
public static void qsort(Comparable[] c){
qsort(c,0,c.length-1);
}
Object graph navigation: GPaths
class Invoice { List items; … }
class Item { Product product; int total() {…} … }
class Product { String name; … }
List<Invoice> invoices = …;
// get all product names where item total > 7000
List result = invoices.items.grep{it.total() > 7000}.product.name
// Java version:
List result = new ArrayList();
for (Iterator<Invoice> i = invoices.iterator(); i.hasNext(); ) {
List items = i.next().getItems();
for (Iterator j = items.iterator(); j.hasNext(); ) {
Item item = (Item) j.next();
if (item.total() > 7000)
result.add(item.getProduct().getName());
}
}
Dynamic Groovy: multimethods
class Equalizer {
boolean equals(Equalizer e) {...}
boolean equals(Object o) {...}
}
Object obj = new Equalizer()
obj.equals(new Equalizer())
Dynamic Groovy: categories
// Dynamically add methods to any class
class PersistenceCategory
static void save(Object
// save object
}
}
use (PersistenceCategory)
// all objects now have
new MyBean().save()
}
{
o) {
{
save() method
Dynamic Groovy: meta programming
Change class/object behavior at runtime
Meta-Object Protocol (MOP)
You can intercept method calls and property
accesses
invokeMethod(...)
getProperty(...)
setProperty(...)
etc
MarkupBuilder
builder = new groovy.xml.MarkupBuilder()
builder.numbersAndSquares {
description 'Numbers and squares'
(3..6).each {
number (value: it, square: it*it)
}
}
<numbersAndSquares>
<description>Numbers and squares</description>
<number value='3' square='9' />
<number value='4' square='16' />
<number value='5' square='25' />
<number value='6' square='36' />
</numbersAndSquares>
SwingBuilder
swing = new SwingBuilder()
frame = swing.frame(title: 'Hello, world') {
panel(layout: new BorderLayout()) {
label(text: 'Hello, world',
constraints: BorderLayout.CENTER)
button(text: 'Exit',
constraints: BorderLayout.SOUTH,
actionPerformed: {
System.exit(0)
})
}
}
frame.pack()
frame.show()
Domain-specific languages (DSL)
A DSL “is a mini-language aiming at
representing constructs for a given domain”
Groovy features for DSLs: add new
methods/properties to classes, override
operators.
E.g. unit manipulation:
println 30.km/h + 2.m/s * 2
println 3 * 3.mg/L
println 1/2.s - 2.Hz
Grails ORM (GORM)
class Book {
String title
String author
Date releaseDate
}
book = Book.get(id) // let's change the title
book.title = 'War and Peace'
book.save()
Book.listOrderByTitle()
Book.findByReleaseDateBetween(startDate, endDate)
Groovy warts
SLOW
Poor IDE support
Write critical areas in Java
Groovy performance rapidly improving
IntelliJ IDEA's JetGroovy coming along nicely
Stack dumps are a pain
Questions/discussion
Thanks for listening!
cwong@makanasolutions.com