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

« Previous Version 2 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:

You can also use a closure to implement an interface with more than one method. The closure will be invoked for each method on the interface. Since you need a closure whose parameter list matches that of all of the methods you typically will want to use an array as the sole parameter. This can be used just as it is for any Groovy closure and will collect all of the arguments in an array. For example:

Implement interfaces with a map

More commonly an interface with multiple methods would be implemented with a map like so:

Note this is a rather contrived example, but illustrates the concept.

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()
impl = [ 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.

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)

Unknown macro: { println "convert" def m = [}

return m
}
}
use (ConversionUtil)

Unknown macro: { ('groovy,grails,gant' as HashMap).each{ println it }

}

  • No labels