Groovy
Like Jython, Groovy is a scripting language for the Java platform. Unlike Jython, which shares the syntax of Python, Groovy’s syntax is close to Java (and Groovy reuses standard Java libraries). As a result, developers do not need to spend lots of time learning Groovy. I like to think of Groovy as Java lite—a less-restricted Java.
Download and Install Groovy
On January 2, 2007, Groovy 1.0 was officially released. This is the version we will download and install. Begin by pointing your Web browser to the official Groovy site and click the Download link. On the resulting web page, click the version 1.0 binary release zip or tar/gz link (as appropriate). Unzip the archive’s contents to a suitable home directory (I chose c:\groovy).
Add the Groovy home directory’s bin directory to the path environment variable to complete the installation. This step will let you run Groovy scripts (via the groovy shell script or the groovy.bat batch file, or via a native launcher—to learn how to build a native launcher, check out this page) from any directory.
A Brief Groovy Tour
Groovy is an interpreted language. To interpret a Groovy program (or script), specify groovy followed by the script’s filename at the command line. Listing 1 presents a simple script—notice the standard .groovy file extension.
Listing 1 groovy.groovy
// groovy.groovy // Groovy supports Jython-style lists. Because of groovy’s dynamic typing, you // do not need to specify a variable’s type. You also don’t need to specify // semicolon terminators. months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] // You can use a Jython-style for loop to output the list’s items. for (month in months) println month // You can use an inclusive range if you want to access list items by index. for (monthIndex in 0..11) println months[monthIndex] // Classes can include properties. class Salesman { String name // name is a property of Salesman } class Author { String name // name is a property of Author } // Object creation is similar to Java. s = new Salesman() // Properties can be accessed directly. s.name = "John Doe" a = new Author() // Properties can be accessed via getter/setter methods -- with or without // surrounding parentheses. a.setName "Jane Smith" people = [s, a] for (i in people) { println i.name i.setName (i.name.reverse()) // name must be of String type outputPerson (i) } // Functions can be defined globally outside of classes. For this function, // any object with a name property can be passed as an argument. def outputPerson(person) { println person.getName () } // The following class demonstrates the usefulness of closures. class Formatter { Object format def doFormat (p, Object[] args) { format.call (p, args) // Invoke closure with initial pattern and a... // ...variable number of arguments. } } // Imports can be placed where needed. import java.text.* // Create a currency formatter closure. curFormatter = { value, Object[] args -> println NumberFormat.getCurrencyInstance ().format (value) } // Create a message formatter closure. msgFormatter = { pattern, Object[] args -> println MessageFormat.format (pattern, args) } // Create a Formatter with a message formatter closure. f = new Formatter (format: msgFormatter) // Format a generic message. f.doFormat ("The date is {0, date}; the time is {0, time}", new java.util.Date()) // Create a Formatter with a closure for strictly formatting currency values. f = new Formatter (format: curFormatter) // Format a currency value. f.doFormat (137.9256)
Listing 1 shows that Groovy is less restrictive than Java: semicolons are not used to terminate statements, types are not specified in non-property variable declarations, parentheses are optional in method calls, and imports are not restricted to the beginning of the source code.
Listing 1 also reveals Groovy’s list data structure, for loop/numeric range (0..11 indicates an inclusive range from 0 through 11; in contrast, 0...11 indicates an exclusive range from 0 through 10), property-access, "define function outside of class", and closure features.
To run this script from the command line, specify groovy groovy.groovy. In response, you will see output that (except for the date and time) is identical to the following output:
Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec John Doe eoD nhoJ Jane Smith htimS enaJ The date is Mar 5, 2007; the time is 6:09:43 PM $137.93
Perhaps the best way to gauge Groovy’s usefulness as a rapid prototyping language is to compare Java source code with its Groovy counterpart. Listing 2 presents a Swing-based text-file viewer’s Java source code.
Listing 2 Viewer.java
// Viewer.java import java.io.*; import java.util.ArrayList; import javax.swing.*; public class Viewer { public static void main (String [] args) { if (args.length != 1) { System.out.println ("usage: java Viewer filename"); return; } ArrayList<String> lines = new ArrayList<String> (); BufferedReader br = null; try { FileReader fr = new FileReader (args [0]); br = new BufferedReader (fr); String line; while ((line = br.readLine ()) != null) lines.add (line); } catch (IOException e) { System.out.println ("unable to read " + args [0]); return; } finally { try { if (br != null) br.close (); } catch (IOException e) { } } JList list = new JList (lines.toArray ()); JFrame frame = new JFrame ("Viewer: " + args [0]); frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); frame.add (new JScrollPane (list)); frame.setSize (300, 300); frame.setVisible (true); } }
The Viewer application requires a single command-line argument, which identifies a text file whose content is to be displayed. Figure 2 shows the result of invoking java Viewer Viewer.java.
Figure 2 A text file’s content is displayed in a scrollable list.
Listing 3 presents the equivalent Viewer.groovy Groovy script—you can view the contents of this script by invoking groovy Viewer.groovy Viewer.groovy.
Listing 3 Viewer.groovy
// Viewer.groovy import java.io.File import java.util.ArrayList import javax.swing.* if (args.length != 1) { println "usage: groovy Viewer.groovy filename" return } lines = new ArrayList<String> () new File (args [0]).eachLine { line -> lines.add line } list = new JList (lines.toArray ()) frame = new JFrame ("Viewer: " + args [0]) frame.setDefaultCloseOperation JFrame.EXIT_ON_CLOSE frame.add new JScrollPane (list) frame.setSize 300, 300 frame.setVisible true
Listing 3 is much shorter than the previous listing. This brevity is due to what you have previously learned about Groovy, and these additional items:
- As with Jython programs, Groovy programs do not require an enclosing function, such as an equivalent to Java’s public static void main(String [] args) method.
- Groovy enhances Java’s File, Reader, and Writer classes with extra methods that take closure arguments. For example, eachLine() iterates over each line in a file and invokes a closure with the line as the closure’s argument.
Java’s try block/catch exception handler/finally cleanup clause are not required. Groovy automatically closes open files when eachLine() finishes iterating, regardless of whether an exception is thrown.
Finally, although Viewer.groovy does not present an enclosing main() function that identifies an array/list of command-line arguments, you can still access these arguments via Groovy’s predefined args array/list.