In part I we explored Groovy by writing a simple script that approximated the value of PI using the Monte Carlo method. In
this installment I want to explore creating classes in Groovy. We'll refactor our script and move some of the logic that lends itself to parallel processing into a simple Groovy class.
Here's our original groovy script:
package com.appistry.demo.groovy totalPoints = 500000 generator = new Random(System.currentTimeMillis()) pointsInCircle = 0 <font color="#ff0000">totalPoints.times { double x = generator.nextDouble() double y = generator.nextDouble() if (Math.sqrt(x * x + y * y) <= 1) pointsInCircle++ }</font> pi = 4.0 * pointsInCircle / totalPoints println "\nApproximating PI using Monte Carlo Method" println "Points Attempted : " + totalPoints println "Points in Circle : " + pointsInCircle println " Approximate PI : " + pi
The point generation loop (marked in red) is the target of our refactoring. We can dole that logic out to multiple cores and/or multiple machines to efficiently generate a lot of points in parallel if we want to. So we'll start simply and pull that loop out into a Groovy class. We'll have to bring along some variables also. Here's our new PointGenerator class:
package com.appistry.demo.groovy class PointGenerator { static computePoints(totalPoints) { def x, y def pointsInCircle = 0 def generator = new Random(System.currentTimeMillis()) totalPoints.times { x = generator.nextDouble() y = generator.nextDouble() if (Math.sqrt(x * x + y * y) <= 1) pointsInCircle++ } return pointsInCircle } }
So what did we learn?
- As mentioned last time, Groovy maps to Java's package scheme, and I'm choosing to use it here.
- We define a public class PointGenerator. It has no constructor. This simple class doesn't need one, so we'll get off into Groovy's constructors at a later time.
- We define a static method computePoints which takes totalPoints. Groovy classes also support non-static methods and member variables of course, but we don't have any interesting ones yet.
- Groovy supports both duck typing and strong typing of data. Throughout our new method, I've not specified datatypes explicitly. Groovy gives you the flexibility of stating a type if you wish. I could have restricted x and y down to doubles. Indeed, if you look back at my original script, I did just that. In the case of the class, I used the "def" directive to declare x and y. Nominally, to a Java developer, "def" is like declaring "Object" to declare a variable, and this is where Groovy's duck typing support comes in.
- One last note on "def," you may have noticed that in the script, totalPoints is initialized without using def, whereas in my class method I used it. That's because in the class definition, def is required.
- Like Ruby and other dynamic languages, a Groovy method returns the last evaluated expression as its return value, unless there is an explicit return statement. In our case, the last evaluated expression, I believe, is totalPoints.times which returns null. So, we explicitly return pointsInCircle.
Now that we've moved that logic into a class, here's our reworked script (with the changed line in red) using the new Groovy class.
package com.appistry.demo.groovy totalPoints = 500000 <font color="#ff0000">pointsInCircle = PointGenerator.computePoints(totalPoints)</font> pi = 4.0 * pointsInCircle / totalPoints println "\nComputing PI using Monte Carlo Method" println "Points Attempted : " + totalPoints println "Points in Circle : " + pointsInCircle println " Approximate PI : " + pi
We'll save the modified script off to compute_pi2.groovy and give it a spin.
$ groovy compute_pi2.groovy Caught: groovy.lang.MissingPropertyException: No such property: PointGenerator for class: com.appistry.demo.groovy.compute_pi2 at com.appistry.demo.groovy.compute_pi2.main(compute_pi2.groovy)
Whoops, no joy. Groovy can't find our new PointGenerator class that the script uses. We need to compile our Groovy class first.
$ groovyc PointGenerator.groovy $
If you poke around now, you'll see a new package directory structured created in the current directory. You'll see two files down there:
$ ls com/appistry/demo/groovy/ PointGenerator$_computePoints_closure1.class PointGenerator.class
The PointGenerator.class is our Groovy class compiled down to a regular Java class file. The word "closure" imbedded in the name PointGenerator$_computePoints_closure1.class tells us a little bit about how closures are handled in Groovy. Incidently, the Groovy homepage has lots of information about closures and the advantages they give over Java's anonymous inner classes.
Okay, let's try it again:
$ groovy compute_pi2.groovy Computing PI using Monte Carlo Method Points Attempted : 500000 Points in Circle : 392558 Approximate PI : 3.140464
Okay, so I've learned a bit about creating classes in Groovy. There's still a lot of unexplored territory around Groovy classes, constructors, and scoping, and what not, all of which is covered by the excellent examples and docs on the Groovy homepage. I'll leave that to those that want to dig further.
Next time I'll hare off in a different direction with Groovy.








Post new comment