Last editor: Dave Cherry, last modified: Aug 3, 2008
A bit more difficult to get your head around this one, but all primitives are actually objects. So you can call methods or even check types on them. For example the times method can be called directly on an integer, such as 5.times. Also note that to convert from one type to another we can use as <Type>. This converts the variable on the left into type after the as keyword. An example of these concepts will probably help.
To determine type dynamically you can still use the instance of operator, you can even use it on a primitive ( 5 instanceof Integer ). Also, to coerce types the as operator is available.
10.times { value ->
println value;
}
assert(5 instanceof Integer)
String s = 10 as String;
println s;
If you read the previous article on groovy, you will already have seen closures, but they were not fully explained.
A closure is a block of code that can be stored in a variable and passed to a method. When passed as a variable, the code block can be executed by simply "calling" the closure ( example: closureName() ). Any parameters passed in when calling will be passed to the closure, and if you want to access them you declare their names before any code in the closure, follow this by a -> symbol. See the example:
// here we define a closure that takes 1 parameter and squares
// the value passed in. No need to use return because the result
// of the last expression is returned automatically.
def squareClosure = { value ->
value * value;
}
// call the closure with a parameter, expect a result.
assert(4 == squareClosure(2))
That's right, any ex C++ programmers out there will remember this one, and how powerful (and dangerous) it can be. Some of the operators can be overloaded, such that a user defined method will run instead of Groovy's own implementation. Frameworks rely on this concept. Many operators such as plus, minus, multiply can be overloaded. For a more complete list see: http://groovy.codehaus.org/Operator+Overloading.
Threading in Groovy follows exactly the same rules as in Java. However, creating a Runnable implementation can be somewhat easier, as this example shows. In order to protect a variable from mutli-threaded access, one does exactly the same as in Java using synchronized and locks.
class ThreadedExample
{
// use a 1.5 concurrent feature to safely increment
// a value by multiple threads.
AtomicInteger counter = new AtomicInteger(0);
// this method will be protected from calls by
// more than one thread as per synchronized.
synchronized syncMethod(toOutput)
{
println(toOutput);
}
void go()
{
// create thread that counts up to 20 calling the
// synchronized method, and updating the value.
def th = new Thread({
for( i in 1..20 )
{
Thread.sleep(100);
syncMethod ("thread loop ${i}")
counter.incrementAndGet()
}
});
// start thread
th.start();
// perform same loop outside thread
for( outer in 1..20 )
{
Thread.sleep(100);
syncMethod ("outer loop ${outer}");
counter.incrementAndGet()
}
// wait for our thread to end
th.join();
assert(counter.get() == 40)
}
}
new ThreadedExample().go();
Comments [2]
On 14-Sep-2008 22:15, Paul King wrote:
I liked your AtomicInteger example so much I thought it deserved to be added (with some slight modifications) to the Groovy documentation:
http://groovy.codehaus.org/Concurrency+with+Groovy
Let me know if this is not OK.
On 17-Sep-2008 05:45, Dave Cherry wrote:
Paul, that is great - glad to be of service.
Dave Cherry.