By Jim Driscoll
Master the basics of Groovy, a general-purpose scripting language that runs on the Java Virtual Machine (JVM).
Published July 2012
Downloads:
Groovy is a general-purpose scripting language that runs on the Java Virtual Machine (JVM) and can largely be viewed as a superset of Java. For example, take the program shown in Listing 1. Is it a Groovy program or a Java program?
public class Hello { String name; public void sayHello() { System.out.println("Hello "+getName()+"!"); } public void setName(String name) { this.name = name; } public String getName() { return name; } public static void main(String[] args) { Hello hello = new Hello(); hello.setName("world"); hello.sayHello(); } }
Listing 1. Example Program
Take your pick—it will compile and run in both environments. This basic program is a bit wordy, and we can certainly do things more simply in Java, but it contains a number of patterns that you’d commonly see, including the use of the bean pattern, as well as the use of the main method to make the class executable via the Java command line. When we run it, it simply prints out “Hello world!,” as is customary in these sorts of things.
To try this out in Java, you can use your favorite IDE. You can also use an IDE to try this in Groovy, but you might just want to use the groovyConsole program, which is available as part of the GDK. Download it now, and play along via cut and paste.
Now, as I said, Groovy is roughly a superset of Java; one difference is that things are public by default. That means we could just as easily use the code shown in Listing 2.
class Hello { String name; void sayHello() { System.out.println("Hello "+getName()+"!"); } void setName(String name) { this.name = name; } String getName() { return name; } static void main(String[] args) { Hello hello = new Hello(); hello.setName("world"); hello.sayHello(); } }
Listing 2. An Alternate Way to Code the Example Program
Accessors and mutators are automatically created for your class variables, so we can also shorten the program by taking those out, as shown in Listing 3:
class Hello { String name; void sayHello() { System.out.println("Hello "+getName()+"!"); } static void main(String[] args) { Hello hello = new Hello(); hello.setName("world"); hello.sayHello(); } }
Listing 3. Shortening the Program
Now we’re getting somewhere. In Groovy, System.out.println
can be shortened to just println
as a convenience, so you can also use the version shown in Listing 4:
class Hello { String name; void sayHello() { println("Hello "+getName()+"!"); } static void main(String[] args) { Hello hello = new Hello(); hello.setName("world"); hello.sayHello(); } }
Listing 4. Further Shortening the Program
There’s also a difference in how Groovy deals with String objects—using double quotation marks with strings allows for variable substitution. There are also strings with single quotation marks, as shown in Listing 5, which do not:
class Hello { String name; void sayHello() { println("Hello $name!"); } static void main(String[] args) { Hello hello = new Hello(); hello.setName('world'); hello.sayHello(); } }
Listing 5. Strings with Double Quotation Marks and Single Quotation Marks
Groovy also allows dot notation for getting and setting fields of classes, just like Java, as shown in Listing 6. Unlike Java, this will actually go through the getter/setter methods (which, you’ll recall, are automatically generated in our current example):
class Hello { String name; void sayHello() { println("Hello $name!"); } static void main(String[] args) { Hello hello = new Hello(); hello.name = 'world'; hello.sayHello(); } }
Listing 6. Dot Notation
Typing information is also optional; instead of specifying a type, you can just use the keyword def
, as shown in Listing 7. Use of def
is mandatory for methods, but it is optional for parameters on those methods. You should also use def
for class and method variables. While we’re at it, let’s take out those semicolons; they’re optional in Groovy.
class Hello { def sayHello(name) { println("Hello $name!") } static def main(args) { Hello hello = new Hello() def name = 'world' hello.sayHello(name) } }
Listing 7. The def
Keyword
OK, that’s nice, but we can make this even shorter. Because Groovy is a scripting language, there’s automatically a wrapping class (called Script
, which will become very important to us later). This wrapping class means that we can get rid of our own wrapping class, as well as the main
method, like so:
def sayHello(name) { println("Hello $name!") } def name = 'world' sayHello(name)
Using an Array
So I started with a simple Java program (which also worked in Groovy) and slowly stripped out the cruft. Now, let’s add a little change to use an array. Since Groovy is roughly a superset of Java, you might be tempted to do something like this:
def sayHello(name) { println("Hello $name!") } String[] names = {"SintSi", "Kaitlyn", "Keira"} for (String name : names) { sayHello(name) }
But this won’t work. This is one place where Java syntax differs from Groovy’s. To create a static array, you’d instead do this:
def sayHello(name) { println("Hello $name!") } String[] names = ["SintSi", "Kaitlyn", "Keira"] for (String name : names) { sayHello(name) }
As before, we can eliminate the type declarations:
def sayHello(name) { println("Hello $name!") } def names = ["SintSi", "Kaitlyn", "Keira"] for (def name : names) { sayHello(name) }
But a more Groovy way of doing the same thing would be to use the in
keyword:
def sayHello(name) { println("Hello $name!") } def names = ["SintSi", "Kaitlyn", "Keira"] for (name in names) { sayHello(name) }
Note that under the hood, this code is no longer creating an array; rather, Groovy is (invisibly) creating an ArrayList
. This gives us a number of new options, for instance, sorting, as shown in Listing 8:
def sayHello(name) { println("Hello $name!") } def names = ["SintSi", "Kaitlyn", "Keira"] names.sort() for (name in names) { sayHello(name) }
Listing 8. Sorting
You can also add entries to and remove entries from the list, as shown in Listing 9:
def sayHello(name) { println("Hello $name!") } def names = ["SintSi", "Kaitlyn", "Keira"] names += 'Jim' names -= 'SintSi' names.sort() for (name in names) { sayHello(name) }
Listing 9. Adding or Removing Entries
But this still isn’t the way that many Groovy coders would do it. They’d probably use the built-in method each
, which takes a closure as an argument. If you aren’t already familiar with closures (I knew them already from JavaScript), they’re similar in many ways to method pointers. And you might as well start learning about them since they’re coming to Java.
To use a closure, you define it using enclosing curly braces, and you can call it with the call
method, like so:
def sayHello(name) { println("Hello $name!") } def clos = {name -> sayHello(name)} clos.call('world')
This will print “Hello world!” Note that if you’re trying this in groovyConsole, you’ll see an additional value at the end, because Groovy scripts always return the last value as the return value, and groovyConsole is showing you the value of the names
ArrayList
. In this example, the name ->
preamble defines a single parameter that the closure takes.
Now let’s use the closure with the each
method, as shown In Listing 10:
def sayHello(name) { println("Hello $name!") } def names = ["SintSi", "Kaitlyn", "Keira"] names += 'Jim' names -= 'SintSi' names.sort() def clos = {name -> sayHello(name)} names.each(clos)
Listing 10. Using the Closure with the each
Method
Under the covers, names.each
is iterating through the collection and passing each value to the closure as the first parameter, just as in our previous example. We can simplify this by creating the closure in-place. And since in Groovy, method parentheses are optional when the method takes one or more parameters, we can use the format shown in Listing 11, which is pretty darn readable:
def sayHello(name) { println("Hello $name!") } def names = ["SintSi", "Kaitlyn", "Keira"] names += 'Jim' names -= 'SintSi' names.sort() names.each {name -> sayHello(name)}
Listing 11. Parentheses Are Optional for Some Methods
One more thing: By default, the first parameter of a closure is named it
. So, you could instead use that, as shown in Listing 12:
def sayHello(name) { println("Hello $name!") } def names = ["SintSi", "Kaitlyn", "Keira"] names += 'Jim' names -= 'SintSi' names.sort() names.each {sayHello(it)}
Listing 12. Final Groovy Program
Conclusion
That’s it for now. If you’ve followed along so far, you’ve gotten more than enough Groovy under your belt to be able to say, “Sure, more or less,” when someone asks, “Do you know any Groovy?”
See Also
About the Author
Jim Driscoll is a Senior Engineer at Oracle, working on the Groovy integration with Oracle Application Development Framework’s model layer, ADFm. He’s especially interested in DSLs and the creation of languages with simple techniques. He has over 30 years experience in computer software, but then, he started when he was still 12. He’s programmed computers for the U.S. Air Force, a now-defunct systems integrator, and a medium-sized hardware vendor before joining Sun’s JavaSoft division in 1996 and then the Oracle ADF team in 2010.
http://www.oracle.com/technetwork/articles/java/groovy-1695411.html