Why Groovy is so groovy or a beginners guide to hacking Groovy

0

This is the first article in a short series of articles on the Groovy programming language. I personally came to Groovy as part of an undercover project to do something quickly while leveraging previous Java experience. I had been contracted to develop a web application and it “had to be in Java”, according to the client, although they had no real hard requirements to speak of. I had been developing in Ruby on Rails for a couple of years so when I had to develop a “Java” web application, I went searching for web frameworks that might be as productive as Ruby on Rails.

I quickly found Grails which used a language that I had not heard of called Groovy. I realized that I could deliver the application in Tomcat with a Java war (web archive) file and the client would never be the wiser. I did have a background in Java and one dynamic language, Ruby, so when I started writing Groovy I would just try something and see if it would work and more often than not it just worked. However, over the months and then years I found many features and libraries in Groovy that really increased my productivity. I also found that with Groovy (and Grails) I could deliver a highly performant application just as quickly as I could in Rails with additional features such as concurrency (using GPars with Groovy) and very high performance, comparable with Java, using static compilation.

Looping in Groovy

The first Groovy features that I wish I had learned sooner were .each{}, .eachWithIndex{}, and .times{} in order to get rid of dreaded for loops. There are plenty of articles that go into how Groovy adds methods to an object and dynamic dispatch so I will not go into those details and just take a more pragmatic appproach of how to get more productive with specific Groovy features. If you want to play around with some Groovy code, the fastest way to get going is to use the Groovy web console at http://groovyconsole.appspot.com/ (preferred as it has better error output) or the Groovy playground at https://groovy-playground.appspot.com/. I would also recommend installing Groovy and Gradle locally if you really want to get into Groovy.

Before we get into using .each{}, it is important to understand Groovy Lists and Maps. In Groovy, like Javascript, you can create a map literal and a list literal like so:

def aMap = [one:'one',two:'two',three:'three']
def aList = ['one','two','three','four']

In Groovy you can define the type or interface of the Map or List reference and this is becoming more common in idomatic Groovy as you can now optionally statically compile Groovy code which requires that the objects are typed:

Map aMap = [one:'one',two:'two',three:'three']
List aList = ['one','two','three','four']

Under the covers, Groovy actually uses Java’s ArrayList for the List and LinkedHashMap for the Map and adds many methods to them, as you will find out. These default implementations are good choices in my opinion and work in 99 percent of cases. If you really need the properties of a specific List or Map implementation then you can always jump into Java in your Groovy program as Java compiles as Groovy and you probably are at the level where you have some detailed performance requirements for your Lists and Maps or you have used them in Java for years and want to in Groovy.
You can also create an empty Map or List literal and then add items to it later.

def someEmptyMap = [:]
someEmptyMap << [mything:42]
println someEmptyMap
def anEmptyList = []
anEmptyList << ['Hello']
println anEmptyList

Again, [] or [:] is an object literal syntax. If you have used Javascript’s object literal syntax then this may seem familiar. However, Groovy does not have the same idea as a generic object literal like Javascripts var someObject = {}; or with ES6 let someObject = {};, only Lists and Maps for now. The left shift &lt;&lt; operator, in Groovy, is used by a Map and a List to append items, in addition to many other syntaxes for adding items or combining lists and maps including the overloaded plus + operator, .plus(), .add(), .addAll and probably more. I still find new jewels of syntactical sugar in the docs.

Object as Key

A common gotcha with Groovy maps is using an object as a key in a Groovy Map. You may have a string created dynamically and then want to use that string as a key in a Map. In that case you have to surround the reference with parenthesis, (), so that it will reference the string value inside the object and not the actual string used as the object reference.

String myKeyString = "The_Answer"
def someEmptyMap = [:]
someEmptyMap << [(myKeyString):42] ``` ## .each{} So, on to the eaches. The basic each syntax is very straightforward: ``` def aList = ['one','two','three','four'] aList.each{println it} ``` At its most basic, the each syntax provides a block with a scope, which is actually a **Groovy Closure** but you don't need to know that to use it, that is looped over for each element in the list, providing a default, untyped, reference to the item with the keyword `it`. Expanding on that, you can provide a specific name to the reference and type the object reference in the loop. ``` def aList = ['one','two','three','four'] aList.each{ String theString -&gt; println theString }

The arrow operator, -&gt; is simply there to separate the inputs and the logic to be executed in the ‘loop’.

.eachWithIndex{}

You also have .eachWithIndex{} that provides an index within the loop. The first parameter is the item in the list and the second is the index.

def aList = ['one','two','three','four'] aList.eachWithIndex{ String theString, index -> println theString println index }

A couple of things to understand about this type of looping. First, you cannot break out of an .each{} block. Also, you can nest them, but you must name your references to avoid confusion, and errors.

def aList = ['1','2','3','4'] def anotherList = [1,2,3,4] aList.each{ text ->
anotherList.each{number ->
if(number == text.toInteger()) {
println number + " " + text
//break, no, can't do that here
}
}
}

If you absolutely want to break out of an each, then you can throw an exception, however most would say that you should avoid this pattern for both readability and performance reasons. If you do use an exeption, you should probably create a custom exception to avoid catching real errors such as FormatExceptions or IOExceptions, etc. and throwing them away, creating a difficult piece of code to debug.

def aList = ['1','2','3','4']
try {
aList.each { string ->
if (string == '3') {
throw new Exception("Break")
}
}
} catch (Exception e) { } // throw away the exception

There are some options within the eaches that provide for other types of logical control. You can return from the loop using the return keyword. Remember, it will continue looping until the end of the List or Map.

def aList = ['1','2','3','4']
def anotherList = [1,2,3,4]
aList.each{ text ->
anotherList.each{number ->
if(number == text.toInteger()) {
println number + " " + text
return
}
}
}

.eachLine{}

In the same vein as each, Groovy adds an eachLine{} method to Strings that can be used on multiline strings, any string with newline characters. One note, a Groovy multiline string created with a triple single quote will contain a newline character as the first character. It is possible to strip that initial newline character by escaping with a backslash. Note, Groovy has both triple single quoted multiline strings and triple double quoted multiline strings, more on those in future articles.

def aMultiLineString = '''\
A multiline string can be created with three single quotes,
and is a Java String with some methods bolted on.
'''
aMultiLineString.eachLine {
if (it =~ /Java/) {
println it
}
}

The .eachline{} method can name both the line reference and the line count, or index in the block.

aMultiLineString.eachLine { theLine, count -&gt;
if (count == 1) {
println theLine
}
}

.times{}

The other quick and neat way to create a loop, again, one that you can’t break out of, is .times{}. I have used this one in many cases. However, due to some implementaiton details, I find that exceptions thrown inside of a times loop seem to be discarded and rethrown as a generic exception. I have had to recode times loops as for loops on multiple occasions. One of my favorite uses of times loops in in cases where I need to create a nested loop.

List matrix = []
10.times { i -&gt;
List array = []
10.times { j -&gt;
array &lt;&lt; j
}
matrix &lt;&lt; array
}
println matrix.toString()

Overall, my approach to development on the Java Virtual Machine is one where I start all my projects in Groovy, occasionally jump into Java, and sometimes mix and match Java classes with Groovy ones. Using Gradle it is relatively trivial to combine Groovy and Java, inherit from either side, and have the best of both worlds. Personally, I tend to avoid inheritance heirarchies but one level of inheritance can be useful. You can blend an object oriented style, when useful, with a functional style, also, when useful. I did spent six months coding Scala, while interesting, it was a breath of fresh air to return to Groovy.

Thats all the Groovy for now, in the next articles we will explore more ways in which Groovy can make your development faster.

Gregory D. Dickson

Gregory D. Dickson

Gregg is a serial CTO with several startups under his belt. Gregg spent two years building voyhoy.com using JVM technologies including Groovy and developed a search algorithm that performed twice as fast as competitive sites.Most recently he has been leading the development of pashiontool.com using Groovy server side and a Javascript single page application built with Aurelia.io.

Linkedin profile
Gregory D. Dickson

Latest posts by Gregory D. Dickson (see all)

Related posts

No blog post found.