Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

Version 1 Next »

Groovy provides some very convenient ways to implement interfaces.

Implement interfaces with a closure

An interface with a single method can be implemented with a closure like so:

new Thread(

Unknown macro: {println "running"}

as Runnable).start()
An interface with multiple methods can be implemented with a map like so:

impl = [
i: 10,
hasNext:

Unknown macro: { impl.i > 0 }

,
next:

Unknown macro: { impl.i-- }

,
]
iter = impl as Iterator
while ( iter.hasNext() )
println iter.next()

interface X

Unknown macro: { void f(); void g(int n); void h(String s, int n); }

You only need to implement those methods that are actually called, but if a method is called that doesn't exist in the map a NullPointerException is thrown. println() x = [ f:

Unknown macro: {println "f called"}

] as X
x.f()
//x.g() // NPE here
If you'd like to handle all methods in the interface the same way you can simply use a closure.

println()
x =

Unknown macro: {println "method called"}

as X
x.f()
x.g(1)
If you'd like to handle methods with any number and types of arguments defined the closure to take an Object[]. This is the Groovy way define a closure (or method also) with variable arguments. This can be very useful to define a tracing object to print all method calls for an interface.

println()
x =

Unknown macro: {Object[] args -> println "method called with $args"}

as X
x.f()
x.g(1)
x.h("hello",2)
If you're want to use a map be careful that you don't accidentally define the map with { }. Can you guess what happens with the following?

println()
x = { f:

} as X
x.f()
x.g(1)
What we've defined here is a closure with a label and a block. Since we've just defined a single closure every method call will invoke the closure. Some languages use {} to define maps so this is an easy mistake until you get used to [] for maps.
User-defined conversions are a customizable feature in Groovy. You can do this with methods, but the 'as' syntax is particularly elegant.
Let's say you'd like to allow conversion of a delimited string to a map whose keys are the string values and the values are a default. Thanks to user-defined conversions and categories you can define this elegantly and keep the scope of the change localized.

class ConversionUtil {
static DEFAULT = 'WAY COOL'
static Map asType(String keys, Class c)
{ println "convert" def m = [:] keys.split(',').each

Unknown macro: { m[it] = DEFAULT }

return m
}
}
use (ConversionUtil)
{ ('groovy,grails,gant' as HashMap).each

Unknown macro: { println it }

}

  • No labels