Hidden features of Groovy?

Viewed 12158
31 Answers

Using the spread-dot operator

def animals = ['ant', 'buffalo', 'canary', 'dog']
assert animals.size() == 4
assert animals*.size() == [3, 7, 6, 3]

This is a shortcut for animals.collect { it.size() }.

The with method allows to turn this:

 myObj1.setValue(10)
 otherObj.setTitle(myObj1.getName())
 myObj1.setMode(Obj1.MODE_NORMAL)

into this

 myObj1.with {
    value = 10
    otherObj.title = name
    mode = MODE_NORMAL
 }

Using hashes as pseudo-objects.

def x = [foo:1, bar:{-> println "Hello, world!"}]
x.foo
x.bar()

Combined with duck typing, you can go a long way with this approach. Don't even need to whip out the "as" operator.

Anyone know about Elvis?

def d = "hello";
def obj = null;

def obj2 = obj ?: d;   // sets obj2 to default
obj = "world"

def obj3 = obj ?: d;  // sets obj3 to obj (since it's non-null)

Finding out what methods are on an object is as easy as asking the metaClass:

"foo".metaClass.methods.name.sort().unique()

prints:

["charAt", "codePointAt", "codePointBefore", "codePointCount", "compareTo",
 "compareToIgnoreCase", "concat", "contains", "contentEquals", "copyValueOf", 
 "endsWith", "equals", "equalsIgnoreCase", "format", "getBytes", "getChars", 
 "getClass", "hashCode", "indexOf", "intern", "lastIndexOf", "length", "matches", 
 "notify", "notifyAll", "offsetByCodePoints", "regionMatches", "replace", 
 "replaceAll", "replaceFirst", "split", "startsWith", "subSequence", "substring", 
 "toCharArray", "toLowerCase", "toString", "toUpperCase", "trim", "valueOf", "wait"]

For testing java code with groovy, object graph builder is amazing:

def company = builder.company( name: 'ACME' ) {
   address( id: 'a1', line1: '123 Groovy Rd', zip: 12345, state: 'JV' )
   employee(  name: 'Duke', employeeId: 1 ){
      address( refId: 'a1' )
   }
}

Standard feature, but still really nice.

ObjectGraphBuilder

(You do need to give any properties of your POJO that are Lists a default value of an empty list rather than null for builder support to work.)

println 
"""
Groovy has "multi-line" strings.
Hooray!
"""

Unlike Java, in Groovy, anything can be used in a switch statement, not just primitive types. In a typical eventPerformed method

switch(event.source) {
   case object1:
        // do something
        break
   case object2:
        // do something
        break
}

In groovy 1.6, regular expressions work with all of the closure iterators (like each, collect, inject, etc) and allow you to easily work with the capture groups:

def filePaths = """
/tmp/file.txt
/usr/bin/dummy.txt
"""

assert (filePaths =~ /(.*)\/(.*)/).collect { full, path, file -> 
        "$file -> $path"
    } ==  ["file.txt -> /tmp", "dummy.txt -> /usr/bin"]

Closures can make all the old try-finally games of resource management go away. The file stream is automatically closed at the end of the block:

new File("/etc/profile").withReader { r ->
    System.out << r
}

Closure-Based Interface Implementation

If you have a typed reference such as:

MyInterface foo

You can implement the entire interface using:

foo = {Object[] args -> println "This closure will be called by ALL methods"} as MyInterface

Alternatively, if you want to implement each method separately, you can use:

foo = [bar: {-> println "bar invoked"}, 
    baz: {param1 -> println "baz invoked with param $param1"}] as MyInterface

@Delegate

class Foo {
    def footest() { return "footest"}   
}

class Bar {
    @Delegate Foo foo = new Foo()     
}

def bar = new Bar()

assert "footest" == bar.footest()

Argument reordering with implicit arguments is another nice one.

This code:

def foo(Map m=[:], String msg, int val, Closure c={}) {
  [...]
}

Creates all these different methods:

foo("msg", 2, x:1, y:2)
foo(x:1, y:2, "blah", 2)
foo("blah", x:1, 2, y:2) { [...] }
foo("blah", 2) { [...] }

And more. It's impossible to screw up by putting named and ordinal arguments in the wrong order/position.

Of course, in the definition of "foo", you can leave off "String" and "int" from "String msg" and "int val" -- I left them in just for clarity.

Related