Full Disclosure: Dierk Koenig and Guillaume Laforge, two of Groovy in Action's authors, are fellow members of the Grails development team, of which I am a part.
Published in conjunction with the official release of Groovy 1.0, Groovy in Action provides the authoritative guide to Groovy development. And as is clear from the thoughtful discussion of each topic, this book comes straight from the source. Dierk Koenig and two of his coauthors are Groovy committers, and one - Guillaume Laforge - is also Groovy's project manager.
The authors have organized the book in a way that benefits both the Groovy newcomer - presumably wanting a complete tour of the language, its idioms, and how to use it - as well as the experienced Groovy developer - perhaps looking for guidance on applying Groovy in a particular context or seeking a reference guide for all things Groovy.
If you're just picking up the book with no prior exposure to Groovy, you'll likely be ready to tear into Groovy full-bore by the end of the first chapter, titled Your way to Groovy. This introductory chapter makes a strong case for Groovy, its ease of use, its incredible Java integration, and its appeal to developers from a variety of backgrounds.
Getting to Know the Groovy Language
From there, it's on to the first of the three core parts of the book. Part 1, The Groovy Language, is essential reading, both for those just discovering Groovy and for the casual Groovy developer desiring a deeper understanding of the language fundamentals. All six chapters of Part 1 deserve cover-to-cover attention.
Beginning with the basics of syntax conventions, data types (or lack thereof), and the Groovy lifecycle, Part 1 eases us into the world of Groovy. We learn that, in Groovy, everything is an object - even the types that Java treats as primitives. Therefore, for example, not only do we have access to the typical arithmetic operators on numeric types, but we can also call the equivalent arithmetic methods on objects of those types. The book makes extensive use of code examples to illustrate each point. Following that precedent, let's fire up the Groovy shell and have a quick look at this behavior in action.
> groovysh
Let's get Groovy!
================
Version: 1.0 JVM: 1.5.0_06-64
Type 'exit' to terminate the shell
Type 'help' for command help
Type 'go' to execute the statements
groovy> def x = 1
groovy> int y = 2
groovy> println x + y
groovy> println x.plus(y)
groovy> println x instanceof Integer
groovy> println y instanceof Integer
groovy> go
3
3
true
true
===> null
groovy>
Here we see that we can invoke real methods on items that, in Java, would be deemed primitives. Considering that x is untyped, and y is declared as an int, we get a sneak peek into Groovy's type inference, as Groovy recognizes both variables as instances of java.lang.Integer. And because everything's an object in Groovy, we see that both the arithmetic operator (+) and its corresponding method (plus) yield the same results. (Just in case any of you C++ developers were holding out for operator overloading in Java, come on over and try it out in Groovy. You've waited long enough.)
Part 1 continues with an exploration of Groovy collections. By this point in the book, anyone coming from a Java background starts to gain a true appreciation for Groovy's concise and highly-expressive nature. We start to realize the readability benefits of writing code that clearly communicates the task at hand and omits much of the syntactic noise we're otherwise accustomed to seeing. Consider, for example, the ease with which we can define a map and the freedom we have in accessing its data.
def myMap = [a:1, b:2, c:3]
assert myMap['a'] == 1
assert myMap.a == 1
assert myMap.get('a') == 1
assert myMap.get('a', 0) == 1 // return 0 if key 'a' is not
// present in the map
The declaration of myMap clearly communicates the programmer's intent, without mandating the rather verbose four lines of code that we'd use in Java (i.e., one line to declare and initialize the map, and three lines to populate its three key-value pairs).
Once we're up to speed on Groovy's excellent support for collections, it's time to unlock the power of closures. Dierk and company give proper treatment to this potentially daunting topic and offer numerous examples of areas where closures can benefit our day-to-day coding. Continuing the theme of concise code, a personal favorite example of mine is the introduction to resource handling with closures:
How many times have you seen code that opens a stream but calls close at the end of the method, overlooking the fact that the close statement may never be reached when an exception occurs while processing? So, it needs to be protected with a try-catch block. No-wait-that should be try-finally, or should it? And inside the finally block, close can throw another exception that needs to be handled. There are too many details to remember, and so resource handling is often implemented incorrectly. With Groovy's closure support, you can put that logic in one place and use it like this:
new File('myfile.txt').eachLine { println it }
The eachLine method of File now takes care of opening and closing the file input stream properly. This guards you from accidentally producing a resource leak of file handles.
Not only does this conciseness benefit the readability of the code, it fundamentally benefits the correctness and maintainability of the program as well.
As we near the end of Part 1, we see the Groovy treatment applied to control structures, including Boolean logic, looping, etc. Here we see such sections as The Groovy truth, already commonly cited on mailing lists as the go-to reference for understanding and debugging Boolean logic in Groovy. In addition to learning the ins and outs of the other control structures, we also learn that switch statements have finally been freed from Java's restriction of supporting only int values. Instead, Groovy provides a much more natural, flexible, and useful implementation of switch statements. The authors offer the example below, attempting to match one of the conditions in the following order: 0, any value in a range (0 through 9), any value in a list (8, 9, or 11), any objects of type Float, or any integers divisible by 3. The value 10 fails to meet any of those conditions, and finally satisfies the regular expression test for values with two characters.
switch (10) {
case 0 : assert false ; break
case 0..9 : assert false ; break
case [8,9,11] : assert false ; break
case Float : assert false ; break
case {it%3 == 0}: assert false ; break
case ~/../ : assert true ; break
default : assert false ; break
}
Part 1 wraps up with a discussion of one of Groovy's key features: its dynamic nature. The final chapter of Part 1 covers Groovy beans, GPath, and most importantly, Groovy's Meta-Object Protocol, which enables us to modify an object's or class's behavior at runtime.
Assembling Your Groovy Toolkit
With an understanding of the Groovy language under our belt, we begin Part 2 of Groovy in Action, which takes us on a tour of the Groovy library. Part 2 begins with a chapter on Groovy builders. Builders are common enough in Groovy - and plenty powerful to boot - that you'll want to make sure you digest this chapter well.
If you welcomed the conciseness and the utility of the various constructs discussed in Part 1, you'll surely want to spend some time with the next chapter - Working with the GDK. The GDK (or Groovy Development Kit) augments the standard Java API to provide a host of convenience methods for everything from interacting with threads to performing various types of I/O. In fact, it's the GDK that adds the handy eachLine method (discussed above) to java.io.File.
The journey though the Groovy library continues with a chapter on using Groovy to simplify database programming tasks and later illustrates just how easily one can work with XML in Groovy. While the content is clear and informative, if you're in a rush, you can safely save these chapters until an XML- or database-related task crosses your path.
In what is perhaps the most important component of Part 2, we find a much-appreciated chapter explaining strategies for Integrating Groovy into our Java applications. Without a doubt, one of the strongest arguments for Groovy is its seamless Java integration. Whether it's a need to leverage existing investments, a desire for static typing in certain areas of an application, or a demand for raw speed, Java will likely continue to play a role in our applications. As a result, the ability to integrate our Java and Groovy components becomes an important consideration in our development efforts.
But what happens when the dependencies between our Java and Groovy classes become anything less than trivial? How do we handle a scenario where a Java class depends on a Groovy class that in turn depends on another Java class? Groovy in Action describes this very common situation as "the chicken and egg dependency problem." The authors provide a hypothetical example of this problem, and thankfully, the solution turns out to be rather non-intrusive. It encourages more diligent use of interfaces, but that's a good idea in its own right. The solution advocates separating our code base into three core modules: 1) Groovy code, 2) Java code, and 3) the interfaces (which should be written in Java) shared between the first two modules. Then, by first compiling the shared interfaces before compiling the Java and Groovy classes, handling dependencies suddenly becomes a very manageable task.
The book stops short of providing a sample build script to go along with this example. And while organizing the build script from scratch should be reasonably straightforward, it's always nice to start from a working model. Due to the sheer importance of this topic and the frequency with which we'll likely want to integrate our Java and Groovy code, we could surely benefit from an end-to-end integration example.
Digging In
In Part 3, the authors move on to Everyday Groovy, beginning with a chapter on tips and tricks for our everyday development tasks and using Groovy to meet common needs. This chapter shows off Groovy as a handy utility language (or "scripting language," if you prefer that vernacular), and we see Groovy as the veritable Swiss army knife that it is. And while we might be tempted to stick with the typical Java approach to solving various problems, the authors point out the equivalent Groovy idioms that often lead to more elegant solutions. We see how the Groovy way tends to (not surprisingly) fit more cleanly into our Groovy development. The chapter concludes with noteworthy suggestions for setting up our workspace in a way that easily facilitates running, debugging, and profiling our Groovy code.
If you're looking for a low-risk, high-reward area for introducing Groovy to your workflow, writing your unit tests in Groovy is a wise choice. Just think, for example, about the amount of data set-up that bogs down your current test cases. Consider the places where you're populating a list or building a map or working with large strings. These areas can all be greatly simplified with the help of Groovy. The next chapter covers everything we need to know to make unit testing fun again with Groovy, all the way from writing the tests to integrating them into our build process.
The authors round out Part 3 with a chapter on using Groovy to automate various tasks on the Windows platform. We learn how use Groovy to create spreadsheets and Word documents, how to interact with the Windows registry, and how Groovy can help with (or perhaps eliminate) many of the repetitive tasks we might otherwise have to perform manually. Like the chapters on database and XML programming, this chapter can likely wait until a Windows-specific need arises.
Not content with the wealth of information provided in the first fifteen chapters, the authors also include a bonus chapter on Grails, the exciting rapid web application development framework built on Groovy, Spring, Hibernate, and other proven technologies. You won't want to miss this chapter. I recommend it, not only because I'm partial to Grails, but because this chapter is presented in a clever and unique style that's just good clean fun.
Dust Shall Not Settle
In all, Dierk and company have delivered the must-have guide to the Groovy language, somehow striking a fitting balance between a friendly introductory text and a handy reference manual. Even after you finish reading Groovy in Action, you'll want to have this book on your shelf open and by your side for all your Groovy work. Whether you're flipping through the appendix to find a quick example of how Groovy makes it easier to work with regular expressions, or you need to remember how variables are scoped within closures, Groovy in Action will earn its place in your library many times over.
About the Author
Jason Rudolph is an Application Architect at Railinc, where he develops software to help trains move more efficiently throughout North America. He recently delivered an industry-wide inspection reporting and management system relied on for operational safety by Fortune 500 railroads, equipment leasing companies, and the Federal Railroad Administration.
Jason's interests include dynamic languages, lightweight development methodologies, improving developer productivity, and a quest to keep programming fun. It's these interests that led Jason to become a Grails committer and evangelist. Jason is the author of the book, Getting Started with Grails, along with several articles involving this exciting framework. Jason holds a degree in Computer Science from the University of Virginia. He currently lives in Raleigh, NC with his wife (who can take a functional web app and make it actually look good) and his dog (who can outrun him, but is no match for squirrels).