2. Presenter's Background
● 1991 Comp. Sci. BS from RIT
● 1996- using Java
● 2000- developing web apps in Java
● 2005- staff at UH ITS/MIS
● 2009- using Groovy
● 2010- app with Groovy/Grails/Geb/Spock
– in production since 2012 June
– LOC: 14K production, 13K test
3. Presentation Objectives
● recognize and understand Groovy code
● get interested in Groovy coding
● (not introducing Spock/Geb/Grails yet)
4. Outline
● What is Groovy?
● Why do I care?
● How is it different?
● How can I use it?
5. What is Groovy?
● dynamic extension of Java
– syntax
– API (GDK)
● enables less code, more clarity
● compiles to Java classes
● seamless integration with Java
● backed by SpringSource/VMware
● good IDE support in
– IntelliJ IDEA (the best, IMHO)
– Eclipse Groovy/Grails (Spring) Tool Suite
6. Syntax
optional literal
; String 'foo'
( ) List ['foo', 'bar']
keyword
public Map [name: 'David', age: 43]
in
return Range 3..7
as
regex Pattern ~/d+/
catch def
multi-line '''hello
types
String world'''
feature example
properties assert URL.'package'.name == 'java.net'
Closure older = employees.findAll {it.age > 39}
GString “$name was ${age - 1} years old last year”
Groovy truth assert age
yet another for loop for (e in employees) {totalAge += e.age}
named params e = new Employee(name: 'David', age: 43)
multiple assignments (first, last) = 'John Doe'.tokenize()
7. Syntax
feature example
default imports java.io.*, java.lang.*, java.net.*, java.util.*
negative/range indexes last = employees[-1]; allButLast = employees[0..-2]
dynamic properties obj[propertyName]
dynamic methods obj.”$methodName”(params)
meta-programming Integer.metaClass.cos << {Math.cos(delegate)}
@InheritConstructors
AST transformations
class MyException extends Exception {}
assert 1 + 1 == 3
power assert | |
2 false
switch (age) {
case [41, 18, 32]: yakudoshi(); break
case 0..17: child(); break
power switch
case {it % 2}: odd(); break
default: even()
}
customizable operators a+b a.plus(b)
8. Syntax
operator meaning name
a ?: b a?a:b Elvis
a?.b a == null ? a : a.b null safe
m(*list) m(list[0], list[1], ...) spread
list*.m() [list[0].m(), list[1].m(), ...] spread-dot
list*.a spread-dot
[list[0].a, list[1].a, ...]
list.a (GPath)
a.&m reference to method m in object a as closure method closure
a.@f direct access to field f dot-at
t =~ s Pattern.compile(s).matcher(t).find() regex find
t ==~ s Pattern.compile(s).matcher(t).matches() regex match
a <=> b a.compareTo(b) handling null spaceship
a == b a.equals(b) handling null, coercion, & Comparable equals
a.is(b) like Java's a == b
9. API (GDK)
method on Object example
is(other) a.is(b), like Java's a == b
isCase(candidate) for power switch and in, e.g., assert 2 in [1, 2, 3]
println(value) println 'hello world'
sleep(millis) sleep 1500
with(closure) employee.with {name = 'Joe'; age--}
on Collection returns example
join(separator) String assert [1, 2, 3].join('|') == '1|2|3'
sort(closure) List youngestFirst = employees.sort {it.age}
sum() Object def totalAge = employees*.age.sum()
max(closure) Object assert ['hi', 'hello', 'hey'].max {it.length()} == 'hello'
flatten() Collection assert [1,[2,3],[[4]],[ ],5].flatten() == [1,2,3,4,5]
groupBy(closure) Map assert [1,2,3,4,5].groupBy {it % 2} == [0:[2,4], 1:[1,3,5]]
10. API (GDK)
iterative method returns example
findAll List older = employees.findAll {it.age > 39}
find Object firstOlder = employees.find {it.age > 39}
any Boolean hasOlder = employees.any {it.age > 39}
every Boolean noYounger = employees.every {it.age > 39}
def totalAge = 0
each void
employees.each {totalAge += it.age}
employees.eachWithIndex { e, i ->
eachWithIndex void println “${e.name} is at index $i”
}
grep(classifier) List davids = employees*.name.grep ~/David.*/
collect List tripleAges = employees.collect {it.age * 3}
11. API (GDK)
method on File returns example
eachFile(closure) void new File('somedir').eachFile {println it}
getText() String pid = new File('app.pid').text.toLong()
readLines() List lines = new File('grammar').readLines()
eachLine(closure) Object file.eachLine {parse(it)}
Object new File('report').withWriter {out ->
withWriter(closure) employees.each {it.write(out)}
}
on String returns example
split() String[] assert 'a b c'.split() == ['a', 'b', 'c']
tokenize(token) List assert '/tmp:/usr'.tokenize(':') == ['/tmp', '/usr']
normalize() String assert 'arnb'.normalize() == 'anb'
find(regex) String assert 'New York, NY 10292-0098'.find(/d{5}/) == '10292'
29. How can I use it?
● same as Java
● scripts, e.g.
– groovy -e "println System.properties['user.home']"
– groovy -e 'println java.sql.Timestamp.valueOf("2012-11-17 06:49:33").time'
– web app stats polling daemon via JMX
● JUnit -> Spock
● Selenium -> Geb
● Spring/Hibernate -> Grails
My 1 st job after college was programming client/server apps in C and X Windows on Unix, for 6 years. Java was released towards the end, and I loved its exceptions, safe memory, garbage collection, and simpler API. Memory management and error handling in C took so much time programming around and debugging, while Java did it automatically or more cleanly, that I couldn't stand C anymore. For example, compare error handling in C with Exceptions in Java...