metagear.de
A Brief, Yet Thorough, Introduction into the Groovy Programming Language and Development Kit

May 2, 2011 · Robert Söding

Preface

If there is one conservative language in the modern programming world, then it's probably Java. Just take closures as an example, which most other languages already support for years. (Closures, finally, are to be integrated into Java 8, which is expected to be released in 2012; however, their functional range to date will be limited.)
When it comes to a programming language's "expressiveness", I, personally, have been always in doubt about that: Programming languages need to be readable, and thus, maintainable, at first place (fortunately, Groovy is, to a large degree). Moreover, when working in teams, rather "exotic" programming languages don't make much sense - the ideal expressiveness of a language ought to be near the common denominator within the team.
Thus, I well decided to work into common Java frameworks over learning languages like Groovy or Scala.
Nonetheless, at some point, I did make myself familiar with Groovy - and the reason was ... the Grails framework, which I consider one of "the" most advanced, at the same time convenient, and yet modularly extensible, web frameworks, at all.
After having read one or two books on Grails, I'd been tempted to do my first Grails project right away. That might have worked, easily, but then again, I'd been so excited about Grails that I wanted to "do it right" just from the beginning.
And so it came that I did my homework on Groovy, learning syntax constructs and functional capabilities, but also estimating Groovy's environmental impact, as well as its "good, bad, and ugly" paradigms. - These are documented in the article at hand.
As Groovy leverages the Java language and its class libraries, readers of this article are supposed to be already proficient in Java. Discussing aspects of the Java language is out of this article's scope.
Feedback and corrections are most welcome and may be directed to . Thanks.

Introduction

Groovy has been created in 2003 by James Strachan, and was first publically introduced in 2004. G2One, the company that had backed Groovy and Grails formerly, has been acquainted by SpringSource in 2008. Current project lead is Guillaume Laforge of the former team.
Compiling to Java bytecode, leveraging the JVM, and being interoperable with Java, Groovy adds the agileness and dynamic of scripting languages like Ruby or Python to Java.
Features include closures, native syntax for collections, regular expressions, variable interpolation into strings (GString), an XPath-like object / property / child object navigation (GPath), and operator overloading.
Groovy's meta programming capabilities allow for extending objects at compile- or runtime, like adding or intercepting methods, altering behaviour, etc.
As almost any Java constructs are valid in Groovy, the learning curve is quite low. Moreover, most Groovy code is quite intuitively understandable.
Besides Groovy's own, built-in, libraries, i.e., for SQL or XML processing, or unit testing, there are several Groovy modules and frameworks available, one of which is the Spring-based Grails framework.

Installing Groovy and Executing Groovy Code

Installing Groovy

Groovy depends on Java. More specifically, executing Groovy files compiled to Java bytecode requires the Java Runtime Environment (JRE).
The Groovy binaries as well as its Windows and Debian setup packages can be downloaded from the Codehaus website. Alternatively, most Linx distributions ought to have the groovy package included in their repositories. (However, as Groovy constantly evolves, the Groovy version that, i.e., Ubuntu ships is rather outdated.)

Executing Groovy Code

The Groovy distribution comes with three commands to execute Groovy code: Additionally, there's the Groovy compiler, groovyc.

Using the Groovy Shell

Using groovysh, code can be interactively executed in the Groovy shell:
$ groovysh
Groovy Shell (1.7.5, JVM: 1.6.0_22)
Type 'help' or '\h' for help.
-------------------------------------------------------------------------------
groovy:000> println "Hello World"
Hello World
===> null
The help command may also take Groovy shell commands as arguments, i.e., help history.
Interestingly, the inspect command opens the Groovy Object Browser on the last evaluated expression:
groovy:000> x = "Hello World"
===> Hello World
groovy:000> inspect
Groovy Object Browser
In the above screenshot, all (meta) methods are listed that are available on an instance of java.lang.String. In addition to the Java methods, Groovy has added a whole bunch of new methods (see chapter The Default Groovy Methods).

Using the Groovy Console

The groovyConsole command starts the Groovy Console to interactively execute Groovy code:
Groovy Console

Using the groovy Command

The groovy command allows for executing Groovy files ...
$ groovy Hello.groovy
Hello World!
or a given command line parameter:
$ groovy -e "println 'Hello World'"
Hello World

Compiling Groovy Source Files

Groovy source files can be compiled to Java classes (Java bytecode) by using the groovyc command, i.e., by entering:
groovyc Hello.groovy
This will create a file named Hello.class - which contains dependencies on the Groovy core runtime. In order to execute it, the groovy-all*.jar file needs to be on the classpath, i.e., (on Ubuntu):
java -cp /usr/share/java/groovy-all.jar:. Hello
The groovy-all.jar file in the above code snippet is a symlink to /usr/share/groovy/embeddable/groovy-all-1.6.4.jar on Ubuntu. Alternatively, if you've downloaded and unpacked the Groovy binary distribution, a corresponding JAR would be $GROOVY_HOME/embeddable/groovy-all*.jar.
The decompiled Java bytecode, finally, doesn't look quite like what you'd expect from a human-readable Java class. It also contains references to a number of Groovy classes that "manage" the resulting Java code, such as invoking method calls, dynamically. (See chapter Meta Programming for more information.)
It's a good idea to take a look at the Java code that Groovy generates by using a Java Decompiler.

Using Groovy from within IDEs

All major Java-based IDEs (Eclipse, NetBeans, IntelliJ IDEA, JDeveloper, and others) support Groovy - either natively or by an external plugin.
IDEA supports Groovy in its community edition, but Grails in its commercial editions, only. As for Eclipse, there's a Groovy plugin, but also the SpringSource Tool Suite, that, moreover, provides Grails support.
Unfortunately, Groovy code may contain "virtual" methods added through meta programming. Additionally, Groovy allows for dynamic typing, where types are resolved at runtime, not at compile time. Thus, object introspection is limited, impacting code completion and secure refactoring. Also, IDE hints like "go to declaration" or "tooltips on mouseover" often don't work.

The Groovy Language

"Groovy", as a language and framework, may be categorized into the language itself, the GDK (Groovy Development Kit), and a set of libraries that shorten up common programming tasks. The following picture shows a corresponding mind map:
Groovy: Language, GDK, Libraries
This article mostly deals with Groovy's language and GDK scopes; the Groovy built-in libraries are left out. (In future Groovy versions, those libraries will be externalized from the core, BTW.)

From Java to Groovy

Almost any Java code construct, and datatype, any type of Java code, is valid in Groovy, as well. As such, Groovy may be regarded a Java superset.
However, some syntax elements are optional in Groovy, including parentheses, return statements, semicolons at the end of statements, and package prefixes for common packages.
Java classes', methods' and properties' accessibility modifiers (public, protected, private, default) apply to Groovy as well, however, the default modifier (which is then omitted) doesn't mean package but public.
Bean properties, such as person.setName(..) or person.getName() can be accessed through their property name, i.e., by person.name = "John", resp., assert person.name == "John", just like in Java's Expression Language (EL).
Groovy automatically imports the following packages:
Mostly due to its dynamic nature - missing compile time checks -, Groovy code often makes heavily use of language-level assertions, i.e.,
x = "hello" 
assert x == "hello"
While Groovy does support Java generic types by syntax, the Groovy compiler doesn't check them and, in fact, strips them off before compilation. That means, a List<Person>'s items can be assigned instances of any type. (Java bytecode as well doesn't contain information on generic types anymore, nevertheless, Java source code that is invalid in this respect won't compile, at least.)

Objects in Groovy

In Groovy, everything is an object: types, methods, operators, closures. Unlike in Java, there are no primitive types (instances may may be declared as int, double, etc., in Groovy, however, are treated like their Java wrappers, like Integer or Double).

The Default Groovy Methods

The GDK (Groovy Development Kit) adds additional methods to Objects and more specific types. Most of these methods are defined by Groovy's DefaultGroovyMethods class. For a compilation of which methods are added to each type, specifically, see the GDK ApiDoc.
Methods that are added to any Object include:
// returns true if the closure returns true for any item:
Boolean         any {closure}
// returns a list of all items that were returned from the closure:
List            collect {closure}      
// same as above, but adds each item to the given collection:
Collection      collect(Collection collection) {closure}       
// simply executes the closure for each item: 
void            each {closure}  
// same as each{} except it passes two aruments: the item and the index:
void            eachWithIndex {closure}         
// returns true if the closure returns true for all items:
Boolean         every {closure}         
// returns the first item that matches the closure expression:
Object          find {closure}  
// returns all items that match the closure expression:
List            findAll {closure}      
// returns the index of the first item that matched the given expression: 
Integer         findIndexOf {closure}
Most of these methods are further described in later chapters of this article.
Notably, the existence of these additional methods does not mean that they would exist anywhere in Java bytecode (by that exact signature). Nevertheless, they are valid Groovy language constructs, and as such get transformed into Java bytecode constructs during the Groovy compilation process (see chapter Meta Programming for an understanding) by using the corresponding methods in, particularly, DefaultGroovyMethods.

Optional Typing

Variables - such as local or instance variables, as well as method or closure return values - may be statically typed, but don't need to be:
Integer age = 22     // statically typed
int age = 22           // statically typed; evaluates to a java.lang.Integer
def age = 22           // dynamically typed; evaluates to a java.lang.Integer
age = 22                // same as above
def age = 22 as Integer // statically typed
If a variable has not been statically typed (by using the def keyword or no qualifier), it is of type Object under the hood. Thus, it can be assigned instances of any other type:
def i = 123
assert i != "123"
i = "123"
assert i == "123"
It should be noted that such a type change may easily cause runtime errors or unexpected data. For instance, Groovy's each(..) method works differently on an integer than on a string.
In contrast to the Java compiler, the Groovy compiler, per default - and per common Groovy paradigm, does not perform compile-time checks on matching types.

Duck Typing

Duck typing means, "if it walks like a duck and quacks like a duck, it must be a duck".
Groovy's runtime provides any object with a large set of additional methods - many of those also for objects of different types. For example, there's the iterating each(..) method on every object. Thus, the object type is easily interchangeable because still the same methods can be used.
Obviously, the same (overloaded) methods may produce different results when operating on objects of different runtime types. For example, the each(..) method may iterate over the items of a collection, the single characters of a string, or, in case of an integer, just iterate one time. - It does not really make sense to use that method with numbers.
In contrast to Java, which selects - overloaded - methods based on an object's static type (and compiles that information into bytecode), Groovy chooses matching methods based on the runtime type of an object.
Duck typing may also lead to absurd behaviour like, true.toBoolean() becoming false: The toBoolean() method exists for Strings, only; however, Groovy "auto-magically" ;-) performs some miscarrying coercion.
There are also the List respondsTo(String, Object[]) and List respondsTo(String) methods, which take a method name (and a number of method parameters) and return a List<MetaMethod>. See the JavaDoc and some sample code for more information.

Simple Data Types

Primitives, like byte, int, and long are all converted into their object wrappers (i.e., Integer) in "everything is an object"-Groovy.
As a result, numeric operations are relatively costly in Groovy because of the then frequent need of conversion between wrappers and their respective primitive types (boxing / unboxing).

Numbers

The default number types in Groovy are Integer and BigDecimal. If a variable is weakly typed, an (alternatively, uppercase or lowercase) ordinal needs to be added to its reference in order to implement a specific runtime type:
def number

number = 0
assert number instanceof Integer

number = 0.0
assert number instanceof BigDecimal

// --------------------------------

number = 0L
assert number instanceof Long

number = 0D
assert number instanceof Double

number = 0G
assert number instanceof BigInteger

number = 0.0G
assert number instanceof BigDecimal
The Groovy runtime adds several additional methods to number instances, including those that normally would be by operators, including plus(..), multiply(..), etc.
In Java, the division of an int by another int results in an int (such as 1 / 2 == 0 becomes true). Interestingly, that's different in Groovy, where int/int divisions always return a BigDecimal:
def bigDecimal0 = 1.div(2)
assert bigDecimal0 == 0.5
assert bigDecimal0 instanceof BigDecimal

def int0 = 1.intdiv(2)
assert int0 == 0
assert int0 instanceof Integer
Other methods of interest include those that faciliate iteration:
def counter 

counter = 0
5.times { counter++ }
assert counter == 5

counter = 0
1.upto(5) { counter++ }
assert counter == 5

counter = 0
5.downto(1) { counter++ }
assert counter == 5

def stepsList = []
0.step(10, 2) { stepsList << it }
assert stepsList == [0, 2, 4, 6, 8]

Object Operators

Operators in Groovy are shortcuts for corresponding methods. For instance, a + b maps to the a.plus(b) method.
Such "operator methods", added to Java classes by the GDK, mainly exist for Collections, Maps, and Numbers - however, they're added to classes of most existing Java types.
Find below a list of operators and mapped methods:
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++ or ++a      a.next()
a-- or --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)
switch(a) { case(b) : }         b.isCase(a)
~a              a.bitwiseNegate()
-a              a.negative()
+a              a.positive() 
The compilation below continues the above list, however, these methods abstain from throwing a java.lang.NullPointerException when evaluating against null:
a == b           a.equals(b) or a.compareTo(b) == 0 
a != b          ! a.equals(b)
a <=> b           a.compareTo(b)
a > b                a.compareTo(b) > 0
a >= b               a.compareTo(b) >= 0
a < b                a.compareTo(b) < 0
a <= b               a.compareTo(b) <= 0 
There are more operators in Groovy (i.e., the dot operator that operates on properties and methods, the collections' spread and subscript operators, RegEx operators, ...).

Operator Overloading

The following code snippet provides an example of (both) overriding and overloading the == and + operators:
class Counter {
    private int count
    
    Counter(int count) {this.count = count}
    
    // override the == operator
    @Override
    boolean equals(Object other) {
        if (!(other instanceof Counter)) 
            return false
            
        return this.count == other.count
    }
    
    int hashCode() {count.hashCode()}
    
    // overload the + operator
    // @Override
    Counter plus(Counter other) {
        if (other == null) 
            return null
            
        return new Counter(this.count + other.count)
    }
}

def counter = new Counter(2)
assert counter == new Counter(2)
assert counter + counter == new Counter(4)
As Groovy uses the reference types of arguments to select an overloaded method (instead of using their static types, like Java does), it would be also possible to overload the boolean equals(Object) method (by boolean equals(Counter)).
Compiling to statically typed Java bytecode using Groovy++' @Typed annotation would change back that behaviour.
BTW, the Groovy compiler does not respect the @Override annotation.

Equality and Identity

In Groovy, the equivalent to Java's boolean equals(Object) method is the == operator, which in Java in turn tests for identity (whether both references share the same address space in memory). To test for identity in Groovy, the Boolean is(Object) is used.

Closures

Closures - like methods - are blocks of code that may take parameters, do operations, call other methods (or closures), and, finally, may return a result. Unlike methods, however, that may return void (nothing), closures always return a value - at least, null.
def printClosure = { println "Hello World!" }

// both calls are equivalent
assert printClosure.call() == null
assert printClosure() == null

def stringClosure = { "Hello World!" }
def nullClosure = { }

assert stringClosure() instanceof String
assert nullClosure() == null
Closures can declare parameters. If a closure does not declare parameters, explicitly, there's always the implicit parameter it. Parameters may have default values. Closures can access variables, methods, etc., in the context of their enclosing class.
def calcClosure = { x, y, z -> 
        x + y + z 
}
assert calcClosure(1, 2, 3) == 6

def classNameClosure = { it.class.name }
assert classNameClosure(1.2) == "java.math.BigDecimal"

def paramClosure = { x, y, z = 0 ->
        x + y + z }
assert paramClosure(1, 2) == 3

def contextVar = 2
def contextClosure = { it * contextVar }
assert contextClosure(3) == 6
Closures can be defined explicitly, by assigning it to a variable, or implicitely. Real objects, they can be passed around - for example, as method parameters.
def printClosure = { println "closure called" }
printClosure() 

def callClosureMethod(closure) {
    closure()
}
callClosureMethod { println "closure called" }
callClosureMethod printClosure

assert [1, 2, 3].find{ it == 1 }.toString() == "1"
Closures can also reference methods:
def quote(context) { 42 }
def quoteClosure = this.&quote

assert quoteClosure(13) != 14
Closures are often used when iterating over collections (and thereby, testing for conditions or transforming items):
def map = [a:1, b:2, c:3]

map.each { println it }
map.each { key, value -> println key + "=" + value }

assert map.findAll { entry -> entry.value < 3 } == [a:1, b:2]
assert map.collect { it.value = it.value * 2 } == [2, 4, 6]
A closure's return statement doesn't propagate beyond the closure's own scope. Therefor, in an iterating method that applies a closure, the closure's return statement will function like continue in a for loop:
counter = 0
[1, 2, 3].each { counter++ }
assert counter == 3

counter = 0
[1, 2, 3].each {
    if (it == 2) return "foo"
    counter++
}
assert counter == 2
Closures have properties that let them access code in (container or other) scopes: this refers to the container class. owner refers to a container closure (if any) or to this. delegate, by default, refers to this, but can also be explicitly set:
class Test {
    def closure = {
        def result = [:]
        result << ["this":        this.class.name]
        result << ["owner":       owner.class.name]
        result << ["delegate":    delegate.class.name]
        
        def nestedClosure = {
            result << ["nested owner": owner.class.name]
        }
        nestedClosure()
    }
}

def testClosure = new Test().closure
testClosure.delegate = new Object()
assert testClosure.call() == [
    "this":            "Test", 
    "owner":           "Test", 
    "delegate":                "java.lang.Object", 
    "nested owner":    'Test$_closure1'
]

Currying

Currying means to take a function that takes multiple parameters, provide some of those parameters with values, and transform it to another function, which takes the same parameters except the ones already provided:
def original = { x, y, z -> return x + y + z }
def curried1 = original.curry(2)
def curried2 = curried1.curry(4)
assert curried2(1) == 7

assert original.getParameterTypes().size() == 3
assert curried1.getParameterTypes().size() == 2
assert curried2.getParameterTypes().size() == 1
Currying is often used to obtain different behavior based on configuration. In the example below, different filter and handler "strategies" get applied.
def compositeIterator = { Closure filter, Closure handler, List valuesList ->
    valuesList.each {
        filter(it) ? handler(it) : null
    }
}

def resultsList = []

def smallNumbersFilter = { it < 3 }
def oddNumbersFilter = { it % 2 == 0 }

def printHandler = { println it }
def addToListHandler = { list, var -> list << var }.curry(resultsList)

def config1 = compositeIterator.curry(smallNumbersFilter, printHandler)
def config2 = compositeIterator.curry(oddNumbersFilter, addToListHandler)

config1(1..5)
config2(1..5)

assert resultsList == [2, 4]
The book Groovy in Action provides an excellent logging system sample, where configuration options include filtering of log messages (whether they contain the strings "debug" or "info"), output formatting (i.e., { line -> "($new Date()): $line" }), and providing an appender (i.e., a console appender). - I just didn't dare to steal that brilliant sample ...

Literals

Groovy Strings

Groovy's GStrings, like Java's Expression Language (EL), support the concept of string interpolation:
def languageName = "Groovy"
def languageType = "dynamically typed"
println "$languageName is a $languageType language"
If the variable portion is more complex, like, it contains spaces or dots, the variable placeholder needs to use curly braces:
println "Current date is: ${new Date()}
The triple-quotation syntax supports multi-line strings:
def person = "Joe"
println """Hello $person,

how are you?"""
Strings in single quotes (') do not support string interpolation.
Groovy also supports slashy syntax, starting and ending with a slash. In such strings backslashes don't need to be escaped. The slashy syntax comes handy with Windows filenames or Regular Expressions, for instance:
def fileName = /C:\Windows\Program Files/
GDK methods added to the String class include:
assert "Hello"[0] == "H"
assert "Hello".getAt(1) == "e"
assert "Hello"[0..2] == "Hel"

assert "Hello".contains("el")
assert "Hello".indexOf("el") == 1

assert "x".padLeft(3, "_") == "__x"
assert "x".padRight(3, "_") == "x__"

assert "I am the walrus".tokenize() == ["I", "am", "the", "walrus"]
assert "hello".capitalize() == "Hello"
assert "Otto".reverse() == "ottO"

def greeting = "Hello"
greeting <<= " World!"
assert greeting instanceof StringBuffer
assert greeting.toString() == "Hello World!"

Regular Expressions

Under the hood, Groovy makes use of the Java java.util.regex.Pattern and java.util.regex.Matcher classes. It is highly recommended to study the corresponding JavaDocs.
Groovy provides support for Regular Expressions at the language level, adding three convenience operators:
Note that compiling a Pattern (see the pattern operator) is costly and slow in relation to applying a Matcher to it. If planning to repeatedly test for matches, it is advisable to compile the Pattern once, and to reuse it.
Related GDK methods include the following:
result = ""
"a1b2c3".eachMatch(/\d/) { result += it }
assert result == "123"
result = ""
def matcher = "a1b2c3" =~ /\d/
matcher.each { result += it }
assert result == "123""
result = "a1b2c3".replaceAll(/\d/) { it - it + "_" }
assert result == "a_b_c_"
The standard pattern notation, such as /\w+/ matches ASCII letters, only. To match Unicode characters, like German Umlauts, French accented characters, or Chinese characters, use an extended notation, i.e.:
def pattern = ~/\p{L}+/
assert pattern.matcher("ä")
assert pattern.matcher("a")
assert ! pattern.matcher("1")
assert ! pattern.matcher("\n")
It is commonly regarded at least good practice to document regular expressions.

Lists, Maps, and Ranges

The semantics of List and Maps are the same in Groovy and Java; however, Groovy adds expressive syntax shortcuts to both. Groovy also introduces the concept of Ranges, that doesn't exist in Java.
On the other hand, Groovy doesn't support Java's arrays by syntax (int[] ints = {1, 2, 3} won't compile in Groovy).
In contrast to Java, the Groovy "collective" types have built-in support for the equals(..) method, by applying that operation to all of their items.

Ranges

Ranges contain a number of elements, that can be iterated through from a left to a right bound.
These elements that ranges contain don't need to be arranged in constant intervals (i.e., "1 2 3 4", "1 2 4 8", "1 3 2 5" are all ranges that can be iterated through), but there is always some kind of strategy that the range will use to determine which element to return next.
Obviously, one can iterate through a range of numbers, or count up a date; however, ranges can contain elements of virtually any object type, including train stations passed on a journey, or species that came up during human evolution in history.
Using Ranges
Ranges can include or exclude their outer bounds, which is expressed by the range operator:
left..right        // inclusive range
left>..<right    // exclusive range
left..<right        // half-exclusive range
The range operator's operator precedence is quite low (lower than a dot operator that connects objects from their methods or properties) so that it is often necessary to put the range operator in brackets.
Like almost anything in Groovy, ranges are objects that can be referenced or assigned methods, etc. (In fact, there's the groovy.lang.Range interface, which Ranges implement).
Find below a number of sample uses of ranges:
// integer range
assert (1..10).contains(10)

// half-exclusive range
assert (1..<10).contains(10) == false
    
// string range
assert ("a".."c").contains("b")

// date range
def today = new Date()
def tomorrow = today + 1
assert (today..tomorrow)[0] == today
assert (today..tomorrow)[1] == tomorrow

// range reference
def r = 1..10
assert r instanceof Range

// loop, and reverse range
def result = ""
for (x in 5..1) {
    result += x
}
assert result == "54321"

// each with closure
result = ""
(1..5).each {
    result += it
}
assert result == "12345"
Implementing a Custom Range
To implement a custom Range,
Find below a simple example:
class IntegerRange implements Comparable {
    int value
    
    IntegerRange(int value) { 
        this.value = value 
    }
    
    int compareTo(Object other) { 
        this.value.compareTo(other.value) 
    }
    
    IntegerRange next() { 
        new IntegerRange(value + 1) 
    }
    
    IntegerRange previous() { 
        new IntegerRange(value - 1) 
    }
}

def min = new IntegerRange(1)
def max = new IntegerRange(5)

def result = ""
(min..max).each { result += it.value }

assert result == "12345"
Under the hood, Groovy will pass two instances (left and right bound) of this custom class to a groovy.lang.ObjectRange instance, which will invoke the next() and previous()methods by meta programming, finally.
Ranges can consist of values of any kind and type, that can be traversed sequentially. Examples include a list of songs in an album, a list of train stations on a journey, or - as in the following sample - a number of phases in a fixed workflow - called Workloads in this case.
class Workload implements Comparable {
    private static final PHASES = ["plan", "implement", "test", "deploy"]
    private int currentPhase
    
    Workload(String phase) { 
        this.currentPhase = PHASES.indexOf(phase) 
    }
    
    @Override
    int compareTo(Object other) { 
        this.currentPhase <=> other.currentPhase 
    }
    
    Workload next() { 
        new Workload(PHASES[currentPhase + 1]) 
    }
    
    Workload previous() { 
        new Workload(PHASES[currentPhase - 1]) 
    }
    
    @Override
    String toString() { 
        PHASES[currentPhase] 
    }
}

def firstPhase = new Workload("plan")
def lastPhase = new Workload("deploy")

def phases = []
(firstPhase..lastPhase).each { phases << it }

assert phases.join(", ") == "plan, implement, test, deploy"

Lists

Lists in Groovy are of type ArrayList by default, which is (like any other List type) ordered.
Groovy does not support generic types (even not at compile time), thus list items can be assigned references of any type.
Specifying Lists
As for creating and specifying lists, there are a number of ways:
// create a list of integers
list = [1, 2, 3]
assert list.size() == 3

// by default, lists are of type java.util.ArrayList
assert list instanceof ArrayList

// explicitly construct an instance of another List type
def linkedList = new LinkedList([1, 2, 3])
assert linkedList instanceof LinkedList
assert linkedList.poll() == 1

// create an empty list
list = []
assert list.size() == 0

// use regular java.util.List methods
linkedList.addAll(list)
assert linkedList.size() == 2

// create a nested list
list = [1, 2, [1, 2, 3]]
assert list[2].size() == 3
assert list[2] == [1, 2, 3]

// lists can take any object type
list = [1, 2, 3.14, "baz", new Object()]
assert list.size() == 5

// generic type information is stripped before compilation
List<Integer> intList = new ArrayList<Integer>([1, 2, 3.14, "baz", new Object()])
assert list.size() == 5
That's all quite intuitive. Notably, however, Groovy does not support Generics, so any object type is valid within a list - including other, then nested, lists.
Accessing and Updating List Elements
List elements are usually accessed, or updated, by using the subscript operator, which may also take a range. Additionally, there are GDK methods that allow for iterating over lists and filtering items.
list = [1, 2, 3]

// using the subscript operator
assert list[0] == 1

// using the GDK method
assert list.getAt(0) == 1

// using a range in a subscript operator
assert list[0..<2] == [1, 2]

// set an element
list[0] = 9; assert list[0] == 9
list.putAt(0, 10); assert list[0] == 10
list[0..1] = [5, 4]; assert list == [5, 4, 3]

// (revert to original list)
list = [1, 2, 3]

// find a single item by condition
assert list.find { it < 3 } == 1

// find all items by condition
assert list.findAll { it < 3 } == [1, 2]

// iterate through a list
result = ""
list.each { result += it }
assert result == "123"
Adding and Removing List Elements
Adding and removing items can be performed by using the appropriate GDK methods (see the DefaultGroovyMethods ApiDocs) or their corresponding operators:
// add an item to a collection 
assert [1, 2, 3] == [1, 2] + 3
// by using the plus(Collection, Object) method
assert [1, 2, 3] == [1, 2].plus(3)

// add another collection
assert [1, 2, 3, 4] == [1, 2] + [3, 4]
// by using the plus(Collection, Collection) method
assert [1, 2, 3, 4] == [1, 2].plus([3, 4])

// add an item to a collection
assert [1, 2, 3] == [1, 2] << 3
// by using the leftShift(Collection, Object) method.
assert [1, 2, 3] == [1, 2].leftShift(3)

// add an item to a collection (same as above),
// but the item is a collection itself,
// so that we'll get a nested list
assert [1, 2, [1, 2, 3]] == [1, 2] << [1, 2, 3]
assert [1, 2, [1, 2, 3]] == [1, 2].leftShift([1, 2, 3])

// remove an item 
assert [1, 3] == [1, 2, 3] - 2
// by using the minus(List, Object) method
assert [1, 3] == [1, 2, 3].minus(2)

// remove an entire collection
assert [1] == [1, 2, 3] - [2, 3]
// by using the minus(List, Collection) method
assert [1] == [1, 2, 3].minus([2, 3])

// multiplying the element instances within the collection
assert [1, 2, 3, 1, 2, 3] == [1, 2, 3] * 2
// by using the multiply(Collection, Number) method
assert [1, 2, 3, 1, 2, 3] == [1, 2, 3].multiply(2)
Using Lists in Control Structures
Lists can be used in control structures as follows:
// an empty list evaluates to boolean false
if ([]) { assert false }
assert [1, 2, 3]

// lists can be traversed in for-loops
def result = ""
for (x in [1, 2, 3]) { result += x }
assert result == "123"

// lists can be traversed by using the each() method
result = ""
[1, 2, 3].each { result += it }
assert result == "123"

// lists can be used in switch statements
switch (2) {
    case [4, 5, 6] : assert false; break
    case [1, 2, 3] : assert true; break
    default : assert false
}
assert [1, 2, 3].isCase(2)

// there are also methods to filter results without looping through a list:
assert [1, 2, 3].intersect([2, 3, 4]) == [2, 3]
assert [1, 2, 3].grep([2, 3, 4]) == [2, 3]

// as for transforming results without looping:
assert [1, 2, 3].collect { it * 2 } == [2, 4, 6]
Manipulating List Elements
There are a number of methods to manipulate list elements:
// integrate nested lists
assert [1, [2, 3]].flatten() == [1, 2, 3]

// reverse list contents
assert [1, 2, 3].reverse() == [3, 2, 1]

// sort a list
assert [3, 1, 2].sort() == [1, 2, 3]
assert ["b", "a", "c"].sort() == ["a", "b", "c"]
assert [true, false, true, false].sort() == [false, false, true, true]

assert ["hi", "hey", "hello"].sort { it.length() } == ["hi", "hey", "hello"]

// remove an item from a list
// by index
def list = ["a", "b", "c"]
assert list.remove(0) == "a"
assert list == ["b", "c"]
// by value
assert list.remove("c") == true
assert list == ["b"]

// remove multiple items from a list
list = [1, 2, 3, 4, 5]
assert list.removeAll([8, 9]) == false
assert list.removeAll([2, 3, 4, 8, 9]) == true
assert list == [1, 5]

// transform a list into another
assert [1, 2, 3].collect { it * 2 } == [2, 4, 6]

// remove null values
assert [1, 2, null].grep { it } == [1, 2]

// remove duplicate values
assert [1, 1, 2].unique() == [1, 2]
More Methods on Lists
The following methods apply for querying for, iterating over, and accumulating list elements:
list = [1, 2, 3]

// query for general information
assert list.size() == 3
assert list.min() == 1
assert list.max() == 3

// find a single item by condition
assert list.find { it < 3 } == 1

// find all items by condition
assert list.findAll { it < 3 } == [1, 2]

// determine if the given closure matches for all list items
assert list.every { it < 3 } == false
assert list.every { it < 4 } == true

// concatenate list items
assert list.join(", ") == "1, 2, 3"

// iterate through a list
result = ""
list.each { result += it }
assert result == "123"

result = ""
list.reverseEach { result += it }
assert result == "321"

// instead of defining the "result" variable outside the closure's own scope,
// we can also pass it
assert list.inject("") { result, element -> result += element } == "123"

Maps

The default implementation in Groovy is a java.util.LinkedHashMap, which, in contrast to a HashMap, is ordered.
Specifying Maps
Maps are built of key/value pairs of the shape [key1:value1, key2:value2, key3, value3], and are accessed by using any key with the subscript operator (i.e., map["key1"].
// create an empty map
def emptyMap = [:]

// create a filled map
def map = ["a":1, "b":2, "c":3]
assert map.size() == 3

// maps, per default, are of type java.util.LinkedHashMap (which is ordered)
assert map instanceof LinkedHashMap

// create a map of another type (TreeMap is sorted)
def treeMap = new TreeMap(map)
assert treeMap == map

// set a value
map["a"] = 2
assert map["a"] == 2

// keys can be specified without quotes 
// if they do not contain special characters or are Groovy keywords
assert [a:1] == ["a":1]

// keys in parentheses map to local variables
def x = "a"
assert [(x):1] == [a:1]
Accessing, Updating, Adding, and Removing Map Entries
A map entry's value is accessed, or assigned, by using the entry's key. Mostly, the key is specified within the subscript operator, however, there are a number of other methods, including using the dot-key syntax.
def map = [a:1, b:2, c:3]

// access a value by key
assert map["a"] == 1

// assign a value
map["a"] = 2
assert map["a"] == 2
// (revert)
map["a"] = 1

// different methods to access a value by key
assert map["a"]                == 1    // subscript operator
assert map.a           == 1    // dot-key syntax
assert map.get("a")    == 1    // JDK method
assert map.get("a", 0) == 1    // default value

// dot-key syntax with keys that contain a dot
def dotMap = ["a.b":1]
assert dotMap."a.b" == 1

// query for a non-existent key
assert map.get("foo")           == null
assert map.get("foo", 0)       == 0 // default value

// NOTE that the latter GDK method has a 
// side effect of potentially inserting a map entry,
// which ought to be considered a design flaw
assert map.containsKey("foo")
// (revert)
map.remove("foo")
assert map.containsKey("foo") == false

// adding a map entry
map.put("d", 4)                // JDK method
map.putAll([e:5])      // JDK method
map.leftShift([f:6])   // GDK method
map << [g:7]             // GDK leftShift operator
map["h"] = 8           // GDK subscript operator

assert map == [a:1, b:2, c:3, d:4, e:5, f:6, g:7, h:8]

// updating an entry
map["a"]        = 8     // subscript operator
assert map["a"] == 8
map.a           = 9     // dot-key syntax
assert map.a    == 9
map << [a:10]             // leftShift operator
assert map["a"] == 10
map.put("a", 1)         // JDK method
assert map["a"] == 1

// removing an entry
assert map.remove("a") == 1
assert map == [b:2, c:3, d:4, e:5, f:6, g:7, h:8]
Using Maps in Control Structures
There are several ways to iterate over a map's entries:
def map = [a:1, b:2, c:3]

def result = ""
map.each { entry ->
    result += entry.key
    result += entry.value
}
assert result.contains("a1")

result = ""
map.each { key, value ->
    result += key
    result += value
}
assert result.contains("a1")

result = ""
map.keySet().each { result += it }
assert result == "abc"

result = ""
for (key in map.keySet()) {
    result += key
}

result = ""
map.values().each { result += it }
assert result == "123"

result = ""
for (value in map.values()) {
    result += value
}
assert result == "123"

// injecting the object to be returned into the closure
// instead of manipulating an object in the outer scope (see the "result" variable above)
assert map.inject([:]) { newMap, entry ->
    entry.value *= 2
    newMap << entry
} == [a:2, b:4, c:6]
More Methods on Maps
Additional methods that operate on maps include the following:
def map = [a:1, b:2, c:3]

// JDK LinkedHashMap, although it is ordered,
// does not override HashMap#equals(Object),
// which does not account for the entries' ordering
def otherMap = [b:2, a:1, c:3]

assert map == otherMap
assert map instanceof LinkedHashMap

// JDK methods
assert map.isEmpty() == false
assert map.size() == 3
assert map.containsKey("a")
assert map.containsValue(1)
assert map.keySet() == new HashSet(["a", "b", "c"])
// (the freakin' HashMap.values() method returns an instance of type 
// HashMap.Values instead of returning a standard List implementation)
assert map.values() != [1, 2, 3]
assert new ArrayList(map.values()) == [1, 2, 3]
// (entrySet() returns an HashMap.EntrySet instance)
assert map.entrySet().class.name == 'java.util.HashMap$EntrySet'

// GDK methods that test if the closures' conditions can be applied
assert map.any { entry -> entry.key == "a" }
assert map.every { entry -> entry.value > 0 }

// obtain a subset of a map
def subMap = map.subMap(["a", "b"])
subMap["a"] != 9
assert map["a"] == 1

// filter all matching entries
assert map.findAll { entry -> entry.value <= 2 } == [a:1, b:2]

// filter all matching entries, and return the first
def firstEntry = map.find { entry -> entry.value <= 2 }
assert firstEntry.key == "a"

// apply some operation on every entry
def entriesList = map.collect { entry -> entry.value *= 2 }
assert entriesList instanceof List
assert entriesList[0].value == 2

Using the * Spread Operator to Spread Collections Apart

Ranges, lists, and maps can be split into their items by using the * spread operator:
def list = [1, 2, 3]
assert [*list, 4, 5] == [1, 2, 3, 4, 5]

def map = [a:1, b:2]
assert [*:map, c:3] == [a:1, b:2, c:3]

def range = 3..5
assert [1, 2, *range] == [1, 2, 3, 4, 5]

// -------------------------------------
def multiply(a, b, c) {
    return a * b * c
}
assert multiply(*list) == 1 * 2 * 3

Control Structures

The Groovy Truth

In Java, conditional expressions must evaluate to boolean, whereas in Groovy, they may apply to any object:
// boolean values
assert true
assert !false

// matchers must match
assert "a" =~ /\w/
assert !("" =~ /\w/)

// collections must not be empty
assert [1]
assert ![]

// maps must not be empty
assert [a:1]
assert ![:]

// strings must not be empty
assert "a"
assert !""

// numbers must not be zero
assert 1
assert -1
assert 1.1
assert 1.1f
assert !0
assert !0.0

// any object must not be null
assert new Object()
assert !null

Miscellaneous Control Structures

The switch Statement

In Java, switch statement classifiers may be of the primitive types byte, short, char, and int (and their respective object wrappers), as well as enums. In contrast, in Groovy, switch classifiers can be of any object type, including Closures, regular expressions' Patterns, and Classes.
switch (1) {
    case 0              : assert false; break;
    case 1.1            : assert false; break;
    case 2..5           : assert false; break;
    case [2, 3, 4]      : assert false; break;
    case {it == 2}      : assert false; break;  // Closure
    case BigInteger     : assert false; break;  // Class
    case ~/\d/          : assert true;  break;  // Pattern
    default             : assert false; break;
}
Unlike in Java, a candidate may match multiple classifiers. Whether or not a candidate is eligible to match a classifier, is determined by the isCase(..) method that is defined in the DefaultGroovyMethods class, and is added to each Groovy object instance by the GDK. (The isCase(..) method may, of course, be overwritten in custom implementations.)
Class a.isCase(b) is implemented as ...
Class a.isInstance(b)
Collection (including Range) a.contains(b)
Number NumberMath.compareTo(a, b) == 0
Object a.equals(b)
Pattern a.matcher(b.toString()).matches()
String a.equals(b)

Assertions

In contrast to Java, where assertions need to be enabled by setting a command line parameter when starting the JVM, assertions in Groovy are enabled by default.
There is a potential controversy about whether to use assertions in production code, or not. - The authors of the book Groovy in Action advocate pro doing so: Assertions did not impact performance too much, and if they did, they could be placed into a static initializer block, for instance. In Java, assertions were seldomly used because they'd need to be enabled - and one could never be sure if they were.
The Groovy Documentation, as well, advocates "Introduce Assertions" as one of the most basic refactoring patterns in Groovy.
In contrast to most assertions in the article at hand, assertions may be guarded with a meaningful message, i.e.:
file = new File("foobar")
assert file.exists(), "File '$file.name' does not exist"

The for loop

The different for loop notations equal Java's except from Groovy's for (variable in iterable) (which is for (variable : iterable) in Java.
Groovy's overloaded DefaultGroovyMethods.iterator(..) methods make many types of objects iterable that are not iterable in Java. (This will also provide an each(..) method to those types.)
If an object can't be made iterable - numbers, for instance -, the body of a for loop will be processed once. If the iterable is null, the for loop's body won't be processed, at all:
def processed
for (x in new Object()) {
    assert x.toString().startsWith("java.lang.Object")
    processed = true
}
assert processed

for (x in null) {
    assert false
}

Return Values

The return statement is optional both in methods and closures. If omitted, the value of the last evaluated expression will be returned. Whereas closures always return a value (null at least), methods that explicitly specify a void return type do not return a value:
void voidMethod() { }
def stringMethod() { "foo" }

// void nullClosure = { } // generates a GroovyCastException
def nullClosure = { }
def stringClosure = { "foo" }

assert voidMethod() == null
assert stringMethod() == "foo"

assert nullClosure() == null
assert stringClosure() == "foo"
In closures used with iteration methods such as each(..), the return statement does not work as one might expect (stop the loop, and, optionally, return a given value). Instead, it functions like Java's continue statement in a for loop:
def counter = 0
(1..5).each {
    if (it == 3) return
    counter++
}
assert counter == 4

Exception Handling

Groovy code does not throw checked exceptions and does not require to declare or catch those when using Java methods that explicitly throw checked exceptions.
The Java compiler, javac, however, complains when checked exceptions are caught where they have not been declared. In such cases it is necessary to add a corresponding throws statement to the code being called.

Dynamic Object Orientation

Fields

As with methods and closures, the default visibility is public. - Groovy doesn't support Java's package default visibility.
Fields can be referenced by using the dot operator (object.fieldName syntax) or the subscript operator:
class Foo {
    def bar
}

def foo = new Foo()

def fieldName = "bar"
foo[fieldName] = "baz"

assert foo.bar == "baz"
foo."$fieldName" will work, too (see chapter Groovy Strings).
Actually, foo.bar does not access the field bar, directly, but one of the accessors getBar() or setBar(..), that have been automatically generated by the Groovy compiler.
A bug feature since Groovy's early days, fields marked as private are still accessible from other classes. Similarly, it's possible to call private methods. - That's the real Groovy magic! ;-)

Methods

As with fields and closures, the default visibility of methods is public. - Groovy doesn't support Java's package default visibility.
Declarations of methods' return types and of parameter types are optional. If omitted, they are untyped and their return value is of type Object or void:
// methods with explicitely typed return values
int intMethod()         {1}
void voidMethod()       { }

// methods with untyped return values
def untypedMethod1()    {1}
def untypedMethod2()    { }

// static methods
static void main(args)  { }
def static main(args)   { }
Unlike Java, Groovy supports optional parameters:
def foo(x, y = 0) { }

Constructors

There are a number of ways to call a constructor with positional parameters:
class Person {
    String firstName, lastName
    
    Person(firstName, lastName) {
        this.firstName = firstName
        this.lastName = lastName
    }
}

def person1 = new Person("John", "Doe")
def person2 = ["John", "Doe"] as Person
Person person3 = ["John", "Doe"]
Note that person2 and person3 are constructed by passing a List that contains the ordered parameters to be passed to the constructor.
When not specifying a constructor, Groovy - just like Java - will create a default constructor. While Java's default (implicit) constructor does not specify constructor arguments, Groovy adds the capability to pass named parameters to the default constructor:
class Person {
    String firstName, lastName
}

new Person()
new Person(firstName: "John")
new Person(firstName: "John", lastName: "Doe")
Under the hood, the Groovy compiler does not actually create any special constructors for named constructor arguments to work. At the calling site, the nullary constructor is invoked, and next, are the corresponding setters. - So, that's no magic, but just a convention for code generation.

Scripts, Classes, the Classpath, and the Groovy Compiler

Groovy files may contain one ore more class definitions and/or code outside of classes. When compiled to Java bytecode using the groovyc command, for each class a single .class file is generated, which name is based on the class' name. Such Groovy classes extend GroovyObject.
Of code outside of class definitions in Groovy files, a distinct .class file is generated, which name is based on the Groovy file's name, extending the abstract Script class, and containing a static void main(..) method.
Like in Java, packages are represented by folders in the file system; so the Groovy compiler will place a class foo.bar.Person in the corresponding subfolder foo/bar. The same rule applies when searching for classes being referenced in code to compile (or execute): They need to be located in a folder hierarchy that matches their package declaration.
Like Java, as well, Groovy uses the classpath concept. groovy and groovyc try to locate referenced classes at the following locations:
The latter configuration option can be set/unset in the $GROOVY_HOME/conf/groovy-starter.conf file. On Ubuntu, it's located at /etc/groovy/groovy-starter.conf.

Multimethods

When it comes to overloaded methods, Java dispatches the call to a method whose parameters matches the static, compile-time, reference types of the variables to pass, i.e.,
public class MethodTest {
        private static String someMethod(String param) {
                return "string";
        }

        private static String someMethod(Object param) {
                return "object";
        }

        public static void main(String[] args) {
                Object objectVar = new Object();
                Object stringVar = new String();
                
                System.out.println(someMethod(objectVar)); // "object"
                System.out.println(someMethod(stringVar)); // "object"
        }
}
Groovy, in contrast, dispatches method calls based on the dynamic, runtime, types:
Object objectVar = new Object()
Object stringVar = new String()

def someMethod(String param) { return "string" }
def someMethod(Object param) { return "object" }

assert someMethod(objectVar) == "object"
assert someMethod(stringVar) == "string"
In consequence, the boolean Object.equals(Object) method can be overloaded in Groovy - not just overwritten as in Java.

GroovyBeans

JavaBeans are objects that Additionally, JavaBeans may have attached events that may inform listeners on state changes, etc.
A typical JavaBean might look like the following code sample:
public class Person implements java.io.Serializable {
        private int id;
        private String name;

        public int getId() { 
                return id;
        }

        public void setId(int id) {
                this.id = id;
        }

        public String getName() {
                return name;
        }

        public void setName(String name) {
                this.name = name;
        }
}
(If no constructor exists, a default constructor will be automatically generated at compile time.) The same bean in Groovy does not have getters and setters:
class Person implements Serializable {
    int id
    String name
}

Automatic Generation of Getters and Setters

The Groovy compiler will automatically add corresponding accessors (getters and setters), and make the fields' accessibility private.
There are a number of rules on how to influence accessors generation: Additionally, if a field is explicitly marked public, for instance, the Groovy compiler will not change that.
The accessors can be accessed as follows:
def person = new Person(id: 1, name: "John")
assert person.id == 1
assert person.getId() == 1

Event Handling

As per JavaBeans specification (and common practice, as well), event listeners can register with a JavaBean to be notified on miscellanious events. Such event listeners implement interfaces that extend the EventListener interface and typically define a single method that the bean will call when a matching event occurs.
In Java, such event listeners are implemented as anonymous inner classes. Doing so with a JButton would be a prominent example:
final JButton button = new JButton("Click me!");
button.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
                System.out.println("Button '" + button.getText()
                        + "' has been clicked.");
        }
});
Note that anonymous inner classes - unlike Groovy closures - can only access final instance variables of their container class.
With the help of an additional method, that Groovy magically adds, and a closure, the above code snippet becomes much more concise in Groovy:
def button = new JButton("Click me!")
button.actionPerformed = {
    println("Button '" + button.text
        + "' has been clicked.");
}

Querying Objects with GPaths

GPath expressions evaluate an object graph of field accesses, property accesses, or method calls. As far as collections (lists, maps, ranges) are involved, the corresponding filters and operations can be applied, as well as the [] subscript operator.
assert String.class.methods.size() == 72
assert String.class.methods.name.grep(~/getC.*/) == ["getChars", "getClass"]
The dot-spread *. operator is used to apply a method to all items in a list, rather than to the list itself:
class Rectangle {
    int width
    int height
    String color
    
    def area() { width * height }
}

def rectangles = [
    new Rectangle(width: 10, height: 15, color: "blue"),
    new Rectangle(width: 20, height: 30, color: "black"),
    new Rectangle(width: 40, height: 60, color: "foo")
]

assert rectangles.width == [10, 20, 40]
assert rectangles.grep{ it.width == 40 }[0].color != "blue"

assert rectangles*.area() == [150, 600, 2400]
In traversing tree structures, like in XML processing, GPath expressions can be used, too. XML attributes are then accessed by using the @ at operator:
def xml = """
<items>
    <item id="1" name="foo" />
    <item id="2" name="bar" />
    <item id="3" name="baz" />
</items>
"""        

def items = new XmlSlurper().parseText(xml)
assert items.item.size() == 3
assert items.item.find{ it.@id == 2 }.@name == "bar"
This article does not actually cover Groovy libraries. GPath expressions' fields of application, however, are not limited to normal POJOs.

Safe Dereferencing with the ?. Operator

When evaluating a path expression, objects within that path may be null; so we'd either need to check for null values in code or catch a NullPointerException. In Groovy, however, the safe dereferencing operator ?. provides an elegant solution for that problem:
class Foo {
    def bar = 1
}

def foo
assert foo?.bar == null

Meta Programming

While Groovy applications are pure Java, Groovy adds additional capabilities to the Java language and existing classes. Changing the behavior of programming languages by the means of programming is called meta programming.
At compile time, the Groovy compiler goes through a multi-phased process of creating an Abstract Syntax Tree (AST) from Groovy application code, that then gets transformed, finally getting transformed to Java bytecode. Within the different phases of that transformation, there are several entry points for programs to alter that process either globally or locally (i.e., per class or package). Application behaviour arisen from compile-time meta programming is statically compiled into Java bytecode.
A non-accidental side effect, compile-time type checks become possible.
Groovy also allows for altering application behaviour, i.e., adding or overriding methods or properties, or by reacting on calls to missing methods, at runtime. Such application behaviour is heavily based on the application's runtime state. For this to work, Groovy employs a complex system of stateful structures, decision rules, and invocation flows, that is involved with each method, constructor, or accessor, call.
While Groovy's runtime meta programming is extremly flexible, it doesn't allow for most compiler checks. Additionally, such code performs worse because of its complexity and dynamic invocation.

Compile-Time Meta Programming

Using Delegation
The delegator pattern is an alternative to using inheritance. The field-level @Delegate annotation makes methods and properties of the composite elements available as if they would natively exist at the container element.
class Swimmer {
    def swim() { "swimming" }
}

class Runner {
    def run() { "running" }
}

class Biker {
    def bike() { "biking" }
}

class Triathlete { 
    @Delegate Swimmer swimmer
    @Delegate Runner runner
    @Delegate Biker biker
}

def triathlete = new Triathlete(
    swimmer: new Swimmer(),
    runner: new Runner(),
    biker: new Biker()
)

triathlete.swim()
triathlete.run()
triathlete.bike()
According to the Groovy documentation, "Replacing Inheritance by Delegation" is one of the most basic design pattern in Groovy refactoring.
Introducing New Methods into Existing Classes Using Categories
New methods can be added to existing classes at compile time.
The methods to be added are defined as static methods in so-called categories. These methods have at least one parameter, where to the first parameter the reference to the delegating object is passed:
class Day {}
class Soul {}

class PersistenceCategory {
    static void save(Day day) {
        println "day saved"
    }
    
    static void save(Soul soul, message) {
        println "life saved, " + message
    }
}
These methods are only accessible from within the use(..) method:
use (PersistenceCategory) {
    new Day().save()
    new Soul().save("thanks")    
}
Optionally, the use(..) method may also provided with a comma-separated list of categories.
Alternatively to the above notation, the @Category annotation can be used.
Intercepting Method Calls of a Target Object
Methods of arbitrary objects (not necessarily GroovyObjects) can be intercepted by implementing the Interceptor interface, decorating the target class with a ProxyMetaClass proxy instance, and assigning the interceptor to the instance.
The Interceptor interface is defined as follows:
public interface Interceptor {
    Object beforeInvoke(Object object, String methodName, Object[] arguments);
    Object afterInvoke(Object object, String methodName, Object[] arguments, Object result);
    boolean doInvoke();
}
The Groovy runtime provides, for example, a TracingInterceptor implementation. It can be used as in the following code snippet:
import org.codehaus.groovy.runtime.StringBufferWriter

class SomeClass {
    def someMethod() {
        return "something"
    }
}

def log = new StringBuffer("\n")
def tracer = new TracingInterceptor()
tracer.writer = new StringBufferWriter(log)

def proxy = ProxyMetaClass.getInstance(SomeClass.class)
proxy.interceptor = tracer

proxy.use {
    assert new SomeClass().someMethod() == "something"
}

assert log.toString() == """
before SomeClass.ctor()
after  SomeClass.ctor()
before SomeClass.someMethod()
after  SomeClass.someMethod()
"""

Runtime Meta Programming

Introduction
Almost all objects in Groovy implement the GroovyObject interface:
public interface GroovyObject {
        Object          invokeMethod(String name, Object args);
        Object          getProperty(String propertyName);
        void            setProperty(String propertyName, Object newValue);
        MetaClass      getMetaClass();
        void            setMetaClass(MetaClass metaClass);
}
Java objects can implement that interface, too, and optionally extend its default implementation, GroovyObjectSupport.
Groovy Scripts are the only objects that do not implement the GroovyObject interface. However, these objects extend GroovyObjectSupport, too.
The GroovyObject's associated MetaClass contains methods for invoking methods, constructors, setting or returning properties (and lots more ...):
public interface MetaClass extends MetaObjectProtocol {
        Object  invokeConstructor(Object[] arguments);
        Object  invokeMethod(Object object, String methodName, Object[] arguments);
        Object  invokeStaticMethod(Object object, String methodName, Object[] arguments);
        Object  getProperty(Object object, String property);
        void    setProperty(Object object, String property, Object newValue);

        // additional methods omitted ...
}
While each GroovyObject has its MetaClass association, a MetaClassRegistry implementation associates MetaClasses with object Classes.
When a method call is processed, it can be - actually - handled by the invokeMethod(..) method of different objects:
  1. the current object's own invokeMethod(..) implementation,
  2. the current object's MetaClass' invokeMethod(..) implementation,
  3. or by a MetaClass' invokeMethod(..) implementation, where the Metaclass instance had been selected by the MetaClassRegistry.
The decision flow for the above options should, to some extend, match the one described below:
Dynamically Expandable Beans (Expando Objects)
Beans that are instances of the Expando class can be created at runtime, on the fly, and can be expanded by dynamically adding properties or methods to them:
def person = new Expando()

// dynamically adding a new property
assert person.name == null
person.name = "Fred"
assert person.name == "Fred"

// dynamically adding a new method
assert person.sayHello == null
person.sayHello = { 
    greeting -> greeting + delegate.name 
}
assert person.sayHello("Hi, my name is ") \
    == "Hi, my name is " + person.name
Using ExpandoMetaClass to Dynamically Add Methods, Etc., to Existing Objects
The MetaClass instance associated with any object in Groovy by default is an instance of ExpandoMetaClass, which can be used to add or overwrite methods, constructors, properties, "borrow" methods, etc.
The following code snippet demonstrates how to add a "meta" method to an existing object:
class Person { }

person = new Person()
person.metaClass.sayHello = { "hello" }

assert person.sayHello() == "hello"
Using GroovyObject's invokeMethod(..) when Methods are Missing
A GroovyObject can handle missing method calls itself:
class Dog {
   def invokeMethod(String name, args) {
       switch (name) {
           case "bark": bark();        break;
           case "yowl": yowl(args[0]);         break;
           default: null
       }
   }
   
   private def bark() {
       println "wow! wow!"
   }
   
   private def yowl(intensity) {
       print "wh"
       intensity.times { print "oooh" }
       println "!"
   }
}

def dog = new Dog();
dog.bark()
// prints "wow! wow!"
dog.yowl(5)
// prints "whooohooohooohooohoooh!"
That's also what Groovy builders do (the sample stems from the Groovy User Guide):
class XmlBuilder {
   def out
   XmlBuilder(out) { this.out = out }
   def invokeMethod(String name, args) {
       out << "<$name>"
       if(args[0] instanceof Closure) {
            args[0].delegate = this
            args[0].call()
       }
       else {
           out << args[0].toString()
       }
       out << "</$name>"
   }
}

def xml = new XmlBuilder(new StringBuffer())
xml.html {
    head {
        title "Hello World"
    }
    body {
        p "Welcome!"
    }
}
Using Mixins
Mixins let one "mix-in" certain aspects or cross-cutting functionality ("abilities") into existing objects. Any public methods, closures, and properties will be inserted or overwritten. The objects to be mixed-in need to have a default (nullary) constructor.
class DrivingAbility {
    def drive() { "driving" }
}

class DivingAbility {
    def dive() { "diving" }
}

class Vehicle { }

Vehicle.mixin([DrivingAbility.class, DivingAbility.class])

def vehicle = new Vehicle()
vehicle.drive()
vehicle.dive()
Alternatively, the @Mixin annotation can be used:
@Mixin([DrivingAbility.class, DivingAbility.class])
class Vehicle { }
While the @Mixin annotation causes the methods to be compiled into the target class by an AST Transformation, the mixin method causes runtime changes only.
Missing explicit documentation on these different concepts may be regarded a flaw. Many Groovy programmers will rely on what Groovy "auto-magically" produces, however lose control of the exact results.

Groovy Performance

Although Groovy code are compiled to Java bytecode, Groovy's performance decreases significantly compared to Java, in almost any case. See a list of benchmarks for that matter.
As sidenotes, Groovy, normally, performs better than pure scripting languages like Ruby or Python. - Groovy, apparently, has been optimized quite a lot over the past years, so older benchmarks may be outdated. - The Grails framework, that builds up on Groovy, (optionally) makes use of aggressive caching at different levels.
Groovy code that under the hood just encapsulates Java code (as being the case with Groovy's File object) usually performs most closely to Java.
Numeric operations are usually slow in Groovy because primitives are employed as their respective wrappers in Groovy, and thus there's a lot of boxing and unboxing. There's no workaround for this kind of problem, so intense numeric operations should be externalized into Java code.
In most cases, however, Groovy's performance decrease stems from Groovy doing runtime meta programming all the time, invoking methods and properties, dynamically. Here's how Jochen Theodorou expresses the problem:
A method invocation in Groovy consists usually of several normal method calls, where the arguments are stored in a array, the classes of the arguments must be retrieved, a key is generated out of them, a hashmap is used to lookup the method and if that fails, then we have to test the available methods for compatible methods, select one of the methods based on the runtime type, create a key for the hasmap and then in the end, do a reflection like call on the method.
While that understanding may apply more accurately or less ;-), Groovy employs that costly invocation strategy even in those cases where, from a primary point of view, invocation based on statically compiled information would perform much better.

Groovy++

Groovy++ is an extension to Groovy that joins into the Groovy compilation process to statically compile Groovy code. "Static compilation", at this place, means to produce Java bytecode as one would expect, and not the whole bunch of invocation calls needed for runtime meta programming.
This behavior can be achieved by simply applying Groovy++' @Typed annotation at the package, type, constructor, or method level.
The @Typed annotation takes two optional parameters: the boolean debug parameter and the values parameter of type TypePolicy, which is an enum of TypePolicy.STATIC (default), TypePolicy.DYNAMIC, and TypePolicy.MIXED. MIXED means to compile statically wherever possible.
Interestingly, Groovy++ joins in to the compiler's AST (Abstract Syntax Tree) Transformation at the latest possible phase, just before bytecode generation. That means, it has to visit the whole number of (meta programming) instructions that the Groovy compiler has generated until then, and to convert them back to "pure Java" instructions.
Evidently, several issues at Groovy++' issue tracker show that Groovy++ isn't mature or stable, at all.

Impacts on Groovy Programming Paradigms

While compile-time metaprogramming (obviously) is not affected by Groovy++' static compilation, portions of runtime metaprogramming are (actually, some constructs get recognized and statically compiled while others aren't - which is somewhat confusing).
With partial static compilation, however, there's a breach of Groovy's paradigm to select overloaded methods by the runtime type of the references to be passed as arguments, whereas in statically compiled Java, always the static type decides (amongst other scopes, this may concern operator overloading and multimethods). - Code within the same application may behave different - whether compiled statically or dynamically.
With nested closures compiled statically, the implicit variable owner is not available (while the Groovy compiler, even in combination with Groovy++, does not throws an error because of that).
There may be many more issues ...
An additional functionality at its credits, Groovy++ does not only compile annotated code statically, but also uses complex algorithms to infer type information to untyped variables or method return values (type inference). In consequence, compile-time type checks become available to to a large extend, even on actually untyped code.

Installing and Using Groovy++

The current Groovy++ 0.2.25 distribution ships with an - apparently patched - Groovy 1.7.5, but will cause basic errors to be thrown when used with Groovy 1.7.5, which, at the time of writing, is the latest stable download at Codehaus, or when used with SpringSource Tool Suite 2.5.0 (as well shipping with Groovy 1.7.5).
To use Groovy++ (considering the @Typed annotation, only), groovypp-*.jar needs to be on the classpath.
The Groovy++ distribution contains the Groovy binaries, so groovyConsole etc. can be used from there.
In IDEs, groovypp-*.jar can be simply added to a project's build path.
As a side effect, Eclipse, unfortunately, fails to generate the Run and Debug menus for Groovy classes and scripts. - Nevertheless, compilation works as expected (as can be seen using a Java decompiler).

Java SE 7's invokedynamic

Java SE 7, which is expected to be released in 2011, will support dynamically typed languages (JSR 292) through invokedynamic bytecode. This will speed up method invocation of dynamically typed languages on the JVM, like Groovy, JRuby, and Jython.
However, there are additional performance bottlenecks (in Groovy, specifically) - selecting a matching target object and method, and preparing the method call (i.e., constructing an arguments list) -, which are not affected by invokedynamic.
It has been estimated that Groovy's metaprogramming code would need to be optimized to take full advantage of the new JVM features.

Environmental Considerations

Quality

Architecture

Groovy is a language that directly extends, and builds upon, Java. Groovy adds an expressive syntax, "bonus" constructs like closures or named parameters, plus - to a large extent - meta programming capabilities (which makes it also quite slow in performance). Its dynamic typing doesn't make use of type inference, and by not supporting generic types, there's an even greater loss of type information when compared to Java ... or Scala.
Scala, in contrast to Groovy, is a clean room implementation of a programming language and is commonly regarded a more consistent and advanced language. Even James Strachan, original creator of Groovy, had admitted:
I can honestly say if someone had shown me the Programming in Scala book [...] back in 2003 I'd probably have never created Groovy.
The aforementioned quote had become more popular than Strachan wanted to mean. ;-) See Strachan's follow-up on that issue.
That is not to say that Scala was superior in every concern. As Groovy can be regarded a superset of the Java language, it ought to be quite familiar to Java programmers, and easy to learn. Scala might be "too expressive" even, and is also focussing on functional programming, which may not be desired. Another important aspect is framework support, which is certainly much better for Groovy.

Code Quality

Groovy's internal code mostly adheres to best practices regarding design patterns, coding conventions, and documentation.

Documentation

Groovy's own documentation is impressingly comprehensive and mostly up-to-date. Nevertheless, it's a bit scattered, i.e., there is no single page, or print, version, and there are no learning trails.
There are lots of external articles on Groovy; however, most of them discuss more specialized aspects than "the whole".
The quantity and quality of printed publications is satisfying; however, slightly outdated, in general. The second edition of Groovy in Action, for instance, had been published as a PDF-only "early access" edition in 2009, and is expected to be finished not before 2011.
Overall, there is plenty of information available, that, however, has to be made out at times.
Personally, I'm missing a normative reference like those that, for example, Spring Core, Hibernate, or any JSRs (Java Specification Requests) provide.

Support

Most public support is provided through Groovy's mailing list. A big plus, most supporters there are competent on the issues, cooperative and helpful, many of them being the Groovy developers theirselves.
There are a few external native-language discussion boards, as well.
As can be seen at the Groovy issue tracker, not every bug is handled properly and in time. Some open bugs may be "marker issues", though.
Moreover, the kind of many issues point up a certain sensivity of the Groovy "magic".

Institutional Backing

Most Groovy core developers are around for several years now, and they're providing the impression of being quite engaged. It is, however, hard to find out to which companies, or institutions, they belong.
According to the Groovy main website, it is acknowledged SpringSource that "sustains and leads" Groovy development. SpringSource is a - strategically important - subsidiary of VMWare, and owner of the Spring framework and the Spring- and Groovy-based Grails framework.

Related Libraries, Modules, and Frameworks

Groovy comes with built-in libraries, faciliating common programming tasks, including the scopes of:
There are also a number of Groovy Modules available, one of which is Griffon, a Grails-like framework for developing desktop applications.
Several external projects are using Groovy, however some of them are outdated.
Beyond Groovy's own libraries, the most important project leveraging Groovy ought to be Grails. Grails is a Ruby on Rails-like web framework, led by SpringSource, written in, and leveraging, Groovy. Like Ruby on Rails, Grails features convention over configuration and, as such, is very easy to use.
Towards the database, Grails uses the GORM object/relational mapper, which is both based on Groovy and Hibernate. Towards the presentation layer, Grails employs a MVC (Model/View/Controller) architecture, part of which are Groovy Server Pages (GSP). It's never been so simple to write custom taglibs or plugins!
Building upon the Spring framework, Grails is robust and most extensible.

Popularity

In terms of quantitative usage relative to other programming languages, Groovy is a niche language. The TIOBE Index states that Groovy's popularity amongst programming languages ranks lower than 0.2%.
According to TIOBE, there had been an increased interest in dynamically typed languages, which currently appears to calm down again:
Dynamically vs. statically typed languages
In Groovy, typing is optional. List items and map values, however, are always untyped.
According to Indeed.com, there are significantly more job offerings applying to Ruby programming than for Groovy, both steadily increasing:
Job Trends (Absolute)
Demand on Groovy skills, however, has a larger growth:
Job Trends (Relative/Growth)
Most conversations related to Groovy (including end user support and developers communication) are handled by Groovy's mailing lists. There appears to be a peak of traffic around 2007, and a current decrease:
Mailing List Messages
It also makes sense to compare absolute and relative indicators of Ruby, JRuby, or Grails
As the term "groovy" is also an adjective, it isn't likely to find Google Trends on that term that are not scattered. Nevertheless, there are trends for related web frameworks. According to those, Grails is not as popular as Ruby on Rails (which, apparently, had experienced quite a hype); however, Grails has been enjoying a relatively constant rate of interest over the last time:
Google Trends on Grails, Ruby on Rails, and Scala / Lift
A young language, Groovy has gained quite a lot attention. To estimate whether further investigation might pay, several indicators should be taken into account:

Evaluation and Conclusion

Basics

The Groovy default methods add real value; particularly, to collections, but also to numbers and strings.
Optional (and weak) typing (even missing type inference) may suit well with rapid prototyping but bears the risk of getting runtime errors because of missing compile-time checks. Additionally, readability, and thus, maintainability, may decrease.
The simple data types in Java (as well as arrays) - although a breach of the object-orientated paradigm - have their sense in respect to operational performance. It ought to be possible to change the way the JVM works under the hood; however, there's always been Java's policy to never breach backwards compatibility.
When refraining from using simple data types, Groovy sacrifices performance in favor of best practices.
Implementing object operators as methods (and then, overloadable methods) brings great developer opportunities and flexibility.

Closures

Closures are vastly superior to Java's anonymous inner classes, and ought to be considered standard constructs in any modern imperative programming language.

Literals

Groovy literals - GStrings, and Groovy's central native syntax for collections - are of major assistance for developers, being well readable and sparing much plumbing code.
Regular expressions are first-class citizens in Groovy, being particularly useful for pattern matching on strings, and collection filtering and transformation.

Control Structures

The "Groovy Truth" - being able to evaluate any object in conditional statements - and the enhanced switch statement overcome Java limitations that are almost solely due to JVM issues. Impacts on performance ought to be minimal, and readability ain't sacrificed.
Optional return values might lead to confusion in some cases, but mostly don't. - Java's concept of checked exceptions had been meant well, but proved to be tedious and error-prone in practice.
There is Groovy's focus on assertions, which improve clarity, and thus, maintainability, and enforce logical checks at runtime. Assertions as a central design pattern, on the other hand, point up Groovy's intrinsic problems arising from potentially missing compile-time type checks and dynamic (method) invocation.

Object Orientation

Properties (getters and setters) of GroovyBeans are automatically generated, following transparent rules. Comparable convenience coding faciliations are also named parameters in constructor calls and optional parameters (having default values) with methods and closures.
Groovy's concept of method selection based on parameters' dynamic / runtime types allows for great flexibility but contradicts the behaviour of statically compiled Java code. When mixing both (by enhancing performance using Groovy++), there is a breach of paradigm within the same application, and, as a result, unexpected runtime behaviour may occur.
GPath object navigation and the null-safe dereferencing operator are expressive and concise syntax facilities.

Meta Programming

Compile-time meta programming allows for implementing composite objects through delegates, and AOP-style (Aspect Orientated Programming) introduction of cross-cutting behaviour through categories, mixins, and interceptors. While any of these methods use different design patterns / APIs, implementation in each case is simple, considering the power of these constructs.
Similarly powerful, but at the cost of performance in general, runtime meta programming - for example, with Expando objects - overshoots the goal of providing "Groovy magic" (at least, this is my personal opinion to date). On the other hand, the highly-customizable possibility of responding to missing methods, as used in Groovy builders, are highly flexible and powerful.

Performance

While Groovy's performance may be better than that of scripting languages, performance significantly decreases when compared to statically compiled Java code.
The Groovy++ library provides simple means to statically compile Groovy code, which improves performance quite a lot; however, that conflicts with Groovy's runtime meta programming concepts. The Groovy-based Grails web framework is offering caching strategies for Groovy code.

Programming Environment

IDE tooling support is naturally weak with dynamic languages like Groovy. IntelliJ IDEA engages in extra efforts, i.e., regarding code completion, using type inference and supporting selected APIs (like the Default Groovy Methods).
In general, missing compile-time checks urge the programmer to write more unit tests.

Conclusion

Groovy adds many convenient and/or powerful features to the Java language, of which closures (and their use with collections), the default Groovy methods, and metaprogramming capabilities, ought to be considered most weighty.
A dynamic language, Groovy suites well for more agile software projects, however might introduce issues regarding scalability and maintainability.
Coming from Java, Groovy is easy to learn. Many Groovy programmers are quite enthusiastic about Groovy capabilities in the beginning, but at a later stage realize Groovy's somewhat "hacked" language design and, in general, disadvantages of dynamically typed languages.

Resources

All links retrieved at the date of publication.

On Groovy

Inside Groovy

Beyond Groovy


Valid XHTML 1.0 Transitional Valid CSS!