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,

Unknown macro: { impl.i > 0 }


Unknown macro: { impl.i-- }

iter = impl as Iterator
while ( iter.hasNext() )

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.g() // NPE here
If you'd like to handle all methods in the interface the same way you can simply use a closure.

x =

Unknown macro: {println "method called"}

as X
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.

x =

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

as X
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?

x = { f:

} as X
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 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