Skip to content

Instantly share code, notes, and snippets.

@gregorydickson
Created July 21, 2017 18:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gregorydickson/55e8ca4a571a382d5a37878a0bfb1b71 to your computer and use it in GitHub Desktop.
Save gregorydickson/55e8ca4a571a382d5a37878a0bfb1b71 to your computer and use it in GitHub Desktop.

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

by Gregory D. Dickson 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. In one instance I was in a startup where I built a concurrent search algorithm and we had a competitor, in the same city no less, using Rails to do the same exact searches (we were both travel websites) and our searches returned in about 13 seconds to their 30 seconds. I attribute this to being able to easily, and easily is the keyword here, create a concurrent multi-threaded algorithm.

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: https://gist.github.com/51b6cb0cf71b87dd6a90adae4c9b8229

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: https://gist.github.com/c7fb6a4f67f8f096817067f2b54c0207

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. https://gist.github.com/ace4cd6b9940d91f31fe95bb9de4e5a4

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 << 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. https://gist.github.com/9a5db876d88be18c85c299b39a8036a9

.each{}

So, on to the eaches. The basic each syntax is very straightforward: https://gist.github.com/ce669a61e83936726b95bf70bba4f276

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. https://gist.github.com/4003a73301f4e07c673b3ba8bc0c369d

The arrow operator, -> 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. https://gist.github.com/4e258b2e6326b3f69990b832aca44b57

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. https://gist.github.com/c73c9233ee12b3aeaa89a6967f7bfe30

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. https://gist.github.com/3e3a348bea09133bdbe9824535028c97

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. https://gist.github.com/aceaa8de67ec9f51b9a6d9f7ce73b28b

.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. https://gist.github.com/ec61ff06a7908713b1726916f4b77a26

The .eachline{} method can name both the line reference and the line count, or index in the block. https://gist.github.com/b8bf7dede7b9f3a1727ba81020bf85c1

.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. https://gist.github.com/7fd8eb1740689b269e8f2e8739ddaca1

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 CTO Pashiontool.com https://github.com/gregorydickson

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment