Most valid Java files are also valid Groovy files. Although the two languages are similar, Groovy code can be more compact, because it does not need all the elements that Java needs. This makes it possible for Java programmers to learn Groovy gradually by starting with familiar Java syntax before acquiring more Groovy
programming idioms. Groovy features not available in Java include both static and
dynamic typing (with the keyword def),
operator overloading, native syntax for lists and
associative arrays (maps), native support for
regular expressions, polymorphic iteration,
string interpolation, added helper methods, and the
safe navigation operator ?. to check automatically for
null pointers (for example, variable?.method(), or variable?.field). Since version 2, Groovy also supports modularity (shipping only the jars that the project uses, thus reducing the size of Groovy's library), type checking, static compilation, Project Coin syntax enhancements,
multicatch blocks and ongoing performance enhancements using the invokedynamic instruction introduced in
Java 7. Groovy natively supports
markup languages such as
XML and
HTML by using an inline
Document Object Model (DOM) syntax. This feature enables the definition and manipulation of many types of heterogeneous data assets with a uniform and concise syntax and programming methodology. Unlike Java, a Groovy source code file can be executed as an (uncompiled)
script, if it contains code outside any class definition, if it is a class with a
main method, or if it is a
Runnable or
GroovyTestCase. A Groovy script is fully parsed, compiled, and generated before executing (similar to Python and Ruby). This occurs under the hood, and the compiled version is not saved as an artifact of the process.
GroovyBeans, properties GroovyBeans are Groovy's version of
JavaBeans. Groovy implicitly generates getters and setters. In the following code, setColor(String color) and getColor() are implicitly generated. The last two lines, which appear to access color directly, are actually calling the implicitly generated methods. class AGroovyBean { String color } def myGroovyBean = new AGroovyBean() myGroovyBean.setColor('baby blue') assert myGroovyBean.getColor() == 'baby blue' myGroovyBean.color = 'pewter' assert myGroovyBean.color == 'pewter' Groovy offers simple, consistent syntax for handling
lists and
maps, reminiscent of Java's
array syntax. def movieList = ['Dersu Uzala', 'Ran', 'Seven Samurai'] // Looks like an array, but is a list assert movieList[2] == 'Seven Samurai' movieList[3] = 'Casablanca' // Adds an element to the list assert movieList.size() == 4 def monthMap = [ 'January' : 31, 'February' : 28, 'March' : 31 ] // Declares a map assert monthMap['March'] == 31 // Accesses an entry monthMap['April'] = 30 // Adds an entry to the map assert monthMap.size() == 4
Prototype extension Groovy offers support for
prototype extension through ExpandoMetaClass, Extension Modules (only in Groovy 2), Objective-C-like
Categories and DelegatingMetaClass. ExpandoMetaClass offers a
domain-specific language (DSL) to express the changes in the class easily, similar to
Ruby's open class concept: Number.metaClass { sqrt = { Math.sqrt(delegate) } } assert 9.sqrt() == 3 assert 4.sqrt() == 2 Groovy's changes in code through prototyping are not visible in Java, since each attribute/method invocation in Groovy goes through the metaclass registry. The changed code can only be accessed from Java by going to the metaclass registry. Groovy also allows overriding methods as getProperty(), propertyMissing() among others, enabling the developer to intercept calls to an object and specify an action for them, in a simplified
aspect-oriented way. The following code enables the class java.lang.String to respond to the hex property: enum Color { BLACK('#000000'), WHITE('#FFFFFF'), RED('#FF0000'), BLUE('#0000FF') String hex Color(String hex) { this.hex = hex } } String.metaClass.getProperty = { String property -> def stringColor = delegate if (property == 'hex') { Color.values().find { it.name().equalsIgnoreCase stringColor }?.hex } } assert "WHITE".hex == "#FFFFFF" assert "BLUE".hex == "#0000FF" assert "BLACK".hex == "#000000" assert "GREEN".hex == null The Grails framework uses metaprogramming extensively to enable
GORM dynamic finders, like User.findByName('Josh') and others.
Dot and parentheses Groovy's syntax permits omitting parentheses and dots in some situations. The following groovy code take(coffee).with(sugar, milk).and(liquor) can be written as take coffee with sugar, milk and liquor enabling the development of
domain-specific languages (DSLs) that look like plain English.
Functional programming Although Groovy is mostly an object-oriented language, it also offers
functional programming features.
Closures According to Groovy's documentation: "Closures in Groovy work similar to a 'method pointer', enabling code to be written and run in a later point in time". Groovy's closures support free variables, i.e. variables that have not been explicitly passed as a parameter to it, but exist in its declaration context,
partial application (that it terms '
currying' this Groovy feature allows closures' parameters to be set to a default parameter in any of their arguments, creating a new closure with the bound value. Supplying one argument to the curry() method will fix argument one. Supplying N arguments will fix arguments 1 .. N. def joinTwoWordsWithSymbol = { symbol, first, second -> first + symbol + second } assert joinTwoWordsWithSymbol('#', 'Hello', 'World') == 'Hello#World' def concatWords = joinTwoWordsWithSymbol.curry(' ') assert concatWords('Hello', 'World') == 'Hello World' def prependHello = concatWords.curry('Hello') //def prependHello = joinTwoWordsWithSymbol.curry(' ', 'Hello') assert prependHello('World') == 'Hello World' Curry can also be used in the reverse direction (fixing the last N arguments) using rcurry(). def power = { BigDecimal value, BigDecimal power -> value**power } def square = power.rcurry(2) def cube = power.rcurry(3) assert power(2, 2) == 4 assert square(4) == 16 assert cube(3) == 27 Groovy also supports
lazy evaluation,
reduce/fold,
infinite structures and
immutability, among others.
JSON and XML processing On JavaScript Object Notation (
JSON) and XML processing, Groovy employs the
Builder pattern, making the production of the data structure less verbose. For example, the following XML: Java object oriented static Ruby functional, object oriented duck typing, dynamic Groovy functional, object oriented duck typing, dynamic, static can be generated via the following Groovy code: def writer = new StringWriter() def builder = new groovy.xml.MarkupBuilder(writer) builder.languages { language(year: 1995) { name "Java" paradigm "object oriented" typing "static" } language (year: 1995) { name "Ruby" paradigm "functional, object oriented" typing "duck typing, dynamic" } language (year: 2003) { name "Groovy" paradigm "functional, object oriented" typing "duck typing, dynamic, static" } } and also can be processed in a streaming way through StreamingMarkupBuilder. To change the implementation to JSON, the MarkupBuilder can be swapped to JsonBuilder. To parse it and search for a functional language, Groovy's findAll method can serve: def languages = new XmlSlurper().parseText writer.toString() // Here is employed Groovy's regex syntax for a matcher (=~) that will be coerced to a // boolean value: either true, if the value contains our string, or false otherwise. def functional = languages.language.findAll { it.paradigm =~ "functional" } assert functional.collect { it.name } == ["Groovy", "Ruby"]
String interpolation In Groovy, strings can be interpolated with variables and expressions by using GStrings: BigDecimal account = 10.0 def text = "The account shows currently a balance of $account" assert text == "The account shows currently a balance of 10.0" GStrings containing variables and expressions must be declared using double quotes. A complex expression must be enclosed in curly brackets. This prevents parts of it from being interpreted as belonging to the surrounding string instead of to the expression: BigDecimal minus = 4.0 text = "The account shows currently a balance of ${account - minus}" assert text == "The account shows currently a balance of 6.0" // Without the brackets to isolate the expression, this would result: text = "The account shows currently a balance of $account - minus" assert text == "The account shows currently a balance of 10.0 - minus" Expression evaluation can be deferred by employing arrow syntax: BigDecimal tax = 0.15 text = "The account shows currently a balance of ${->account - account*tax}" tax = 0.10 // The tax value was changed AFTER declaration of the GString. The expression // variables are bound only when the expression must actually be evaluated: assert text == "The account shows currently a balance of 9.000"
Abstract syntax tree transformation According to Groovy's own documentation, "When the Groovy compiler compiles Groovy scripts and classes, at some point in the process, the source code will end up being represented in memory in the form of a Concrete Syntax Tree, then transformed into an Abstract Syntax Tree. The purpose of AST Transformations is to let developers hook into the compilation process to be able to modify the AST before it is turned into bytecode that will be run by the JVM. AST Transformations provides Groovy with improved compile-time metaprogramming capabilities allowing powerful flexibility at the language level, without a runtime performance penalty." Examples of ASTs in Groovy are: • Category and
Mixin transformation • Immutable AST Macro • Newify transformation • Singleton transformation among others. The testing framework
Spock uses AST transformations to allow the programmer to write tests in a syntax not supported by Groovy, but the relevant code is then manipulated in the AST to valid code. An example of such a test is: def "maximum of #a and #b is #c" () { expect: Math.max (a, b) == c where: a | b || c 3 | 5 || 5 7 | 0 || 7 0 | 0 || 0 }
Traits According to Groovy's documentation, "
Traits are a structural construct of the language that allows: composition of behaviors, runtime implementation of interfaces, behavior overriding, and compatibility with static type checking/compilation." Traits can be seen as
interfaces carrying both default implementations and state. A trait is defined using the trait keyword: trait FlyingAbility { /* declaration of a trait */ String fly() { "I'm flying!" } /* declaration of a method inside a trait */ } Then, it can be used like a normal interface using the keyword implements: class Bird implements FlyingAbility {} /* Adds the trait FlyingAbility to the Bird class capabilities */ def bird = new Bird() /* instantiate a new Bird */ assert bird.fly() == "I'm flying!" /* the Bird class automatically gets the behavior of the FlyingAbility trait */ Traits allow a wide range of abilities, from simple composition to testing. == Groovy Version History ==