Groovy | |
---|---|
![]() Groovy Logo | |
Paradigm | Multi-paradigm:object-oriented,imperative,functional,aspect-oriented,scripting |
Designed by | James Strachan |
Developer | Paul King (PMC Chair) Jochen Theodorou (Tech Lead) Guillaume Laforge Cedric Champeau Daniel Sun Eric Milles |
First appeared | 2003; 22 years ago (2003) |
Stable release | 4.0.27[1] ![]() |
Typing discipline | Dynamic,static,strong,duck |
Platform | Java SE |
License | Apache License 2.0 |
Filename extensions | .groovy, .gvy, .gy, .gsh [2] |
Website | groovy-lang![]() |
Majorimplementations | |
Gradle,Grails | |
Influenced by | |
Java,Python,Ruby,Smalltalk,Perl | |
Influenced | |
Kotlin |
Apache Groovy is aJava-syntax-compatibleobject-orientedprogramming language for theJava platform. It is both a static anddynamic language with features similar to those ofPython,Ruby, andSmalltalk. It can be used as both aprogramming language and ascripting language for the Java Platform, is compiled toJava virtual machine (JVM)bytecode, and interoperates seamlessly with other Java code andlibraries. Groovy uses acurly-bracket syntax similar to Java's. Groovy supportsclosures, multiline strings, andexpressions embedded in strings. Much of Groovy's power lies in itsAST transformations, triggered through annotations.
Groovy 1.0 was released on January 2, 2007, and Groovy 2.0 in July, 2012. Since version 2, Groovy can becompiled statically, offeringtype inference and performance near that of Java.[3][4] Groovy 2.4 was the last major release underPivotal Software's sponsorship which ended in March 2015.[5] Groovy has since changed its governance structure to a Project Management Committee inthe Apache Software Foundation.[6]
James Strachan first talked about the development of Groovy on his blog in August 2003.[7] In March 2004, Groovy was submitted to theJava Community Process (JCP) as JSR 241[8] and accepted by ballot. Several versions were released between 2004 and 2006. After the JCP standardization effort began, the version numbering changed, and a version called "1.0" was released on January 2, 2007. After various betas and release candidates numbered 1.1, on December 7, 2007, Groovy 1.1 Final was released and immediately renumbered as Groovy 1.5 to reflect the many changes made.
In 2007, Groovy won the first prize at JAX 2007 innovation award.[9] In 2008,Grails, a Groovyweb framework, won the second prize at JAX 2008 innovation award.[10]
In November 2008,SpringSource acquired the Groovy and Grails company (G2One).[11] In August 2009VMware acquired SpringSource.[12]
In April 2012, after eight years of inactivity, the Spec Lead changed the status of JSR 241 to dormant.[8]
Strachan had left the project silently a year before the Groovy 1.0 release in 2007.[citation needed] In Oct 2016, Strachan stated "I still love groovy (jenkins pipelines are so groovy!), java, go, typescript and kotlin".[13]
On July 2, 2012, Groovy 2.0 was released, which, among other new features, added static compiling andstatic type checking.
When thePivotal Software joint venture was spun-off byEMC Corporation (EMC) and VMware in April 2013, Groovy and Grails formed part of its product portfolio. Pivotal ceased sponsoring Groovy and Grails from April 2015.[5]That same month, Groovy changed its governance structure from a Codehaus repository to a Project Management Committee (PMC) in theApache Software Foundation via its incubator.[6]Groovy graduated from Apache's incubator and became a top-level project in November 2015.[14]
On February 7, 2020, Groovy 3.0 was released.[15] Version 4.0 was released on January 25, 2022.[16]
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.[17] This makes it possible for Java programmers to learn Groovy gradually by starting with familiar Java syntax before acquiring more Groovyprogramming idioms.[18]
Groovy features not available in Java include both static anddynamic typing (with the keyworddef
),operator overloading, native syntax for lists andassociative arrays (maps), native support forregular expressions, polymorphic iteration,string interpolation, added helper methods, and thesafe navigation operator?.
to check automatically fornull pointers (for example,variable?.method()
, orvariable?.field
).[19]
Since version 2, Groovy also supports modularity (shipping only thejar
s 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 theinvokedynamic
instruction introduced inJava 7.[20]
Groovy natively supportsmarkup languages such asXML andHTML by using an inlineDocument 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.[citation needed]
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 amain method, or if it is aRunnable orGroovyTestCase. 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.[21]
GroovyBeans are Groovy's version ofJavaBeans. Groovy implicitly generates getters and setters. In the following code,setColor(String color)
andgetColor()
are implicitly generated. The last two lines, which appear to access color directly, are actually calling the implicitly generated methods.[22]
classAGroovyBean{Stringcolor}defmyGroovyBean=newAGroovyBean()myGroovyBean.setColor('baby blue')assertmyGroovyBean.getColor()=='baby blue'myGroovyBean.color='pewter'assertmyGroovyBean.color=='pewter'
Groovy offers simple, consistent syntax for handlinglists andmaps, reminiscent of Java'sarray syntax.[23]
defmovieList=['Dersu Uzala','Ran','Seven Samurai']// Looks like an array, but is a listassertmovieList[2]=='Seven Samurai'movieList[3]='Casablanca'// Adds an element to the listassertmovieList.size()==4defmonthMap=['January':31,'February':28,'March':31]// Declares a mapassertmonthMap['March']==31// Accesses an entrymonthMap['April']=30// Adds an entry to the mapassertmonthMap.size()==4
Groovy offers support forprototype extension throughExpandoMetaClass
, Extension Modules (only in Groovy 2), Objective-C-likeCategories andDelegatingMetaClass
.[24]
ExpandoMetaClass
offers adomain-specific language (DSL) to express the changes in the class easily, similar toRuby's open class concept:
Number.metaClass{sqrt={Math.sqrt(delegate)}}assert9.sqrt()==3assert4.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 asgetProperty()
,propertyMissing()
among others, enabling the developer to intercept calls to an object and specify an action for them, in a simplifiedaspect-oriented way. The following code enables the classjava.lang.String
to respond to thehex
property:
enumColor{BLACK('#000000'),WHITE('#FFFFFF'),RED('#FF0000'),BLUE('#0000FF')StringhexColor(Stringhex){this.hex=hex}}String.metaClass.getProperty={Stringproperty->defstringColor=delegateif(property=='hex'){Color.values().find{it.name().equalsIgnoreCasestringColor}?.hex}}assert"WHITE".hex=="#FFFFFF"assert"BLUE".hex=="#0000FF"assert"BLACK".hex=="#000000"assert"GREEN".hex==null
The Grails framework uses metaprogramming extensively to enableGORM dynamic finders, likeUser.findByName('Josh')
and others.[25]
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
takecoffeewithsugar,milkandliquor
enabling the development ofdomain-specific languages (DSLs) that look like plain English.
Although Groovy is mostly an object-oriented language, it also offersfunctional programming features.
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".[26] 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'[27]), delegation, implicit, typed and untyped parameters.
When working on Collections of a determined type, the closure passed to an operation on the collection can be inferred:
list=[1,2,3,4,5,6,7,8,9]/* * Non-zero numbers are coerced to true, so when it % 2 == 0 (even), it is false. * The type of the implicit "it" parameter can be inferred as an Integer by the IDE. * It could also be written as: * list.findAll { Integer i -> i % 2 } * list.findAll { i -> i % 2 } */defodds=list.findAll{it%2}assertodds==[1,3,5,7,9]
A group of expressions can be written in a closure block without reference to an implementation and the responding object can be assigned at a later point using delegation:
// This block of code contains expressions without reference to an implementationdefoperations={declare5sum4divide3print}
/* * This class will handle the operations that can be used in the closure above. Another class * could be declared having the same methods, but using, for example, webservice operations * in the calculations. */classExpression{BigDecimalvalue/* * Though an Integer is passed as a parameter, it is coerced into a BigDecimal, as was * defined. If the class had a 'declare(Integer value)' method, it would be used instead. */defdeclare(BigDecimalvalue){this.value=value}defsum(BigDecimalvalueToAdd){this.value+=valueToAdd}defdivide(BigDecimaldivisor){this.value/=divisor}defpropertyMissing(Stringproperty){if(property=="print")printlnvalue}}
// Here is defined who is going to respond the expressions in the block of code above.operations.delegate=newExpression()operations()
Usually calledpartial application,[27] 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 thecurry()
method will fix argument one. Supplying N arguments will fix arguments 1 .. N.
defjoinTwoWordsWithSymbol={symbol,first,second->first+symbol+second}assertjoinTwoWordsWithSymbol('#','Hello','World')=='Hello#World'defconcatWords=joinTwoWordsWithSymbol.curry(' ')assertconcatWords('Hello','World')=='Hello World'defprependHello=concatWords.curry('Hello')//def prependHello = joinTwoWordsWithSymbol.curry(' ', 'Hello')assertprependHello('World')=='Hello World'
Curry can also be used in the reverse direction (fixing the last N arguments) usingrcurry()
.
defpower={BigDecimalvalue,BigDecimalpower->value**power}defsquare=power.rcurry(2)defcube=power.rcurry(3)assertpower(2,2)==4assertsquare(4)==16assertcube(3)==27
Groovy also supportslazy evaluation,[28][29]reduce/fold,[30]infinite structures andimmutability,[31] among others.[32]
On JavaScript Object Notation (JSON) and XML processing, Groovy employs theBuilder pattern, making the production of the data structure less verbose. For example, the following XML:
<languages><languageyear="1995"><name>Java</name><paradigm>objectoriented</paradigm><typing>static</typing></language><languageyear="1995"><name>Ruby</name><paradigm>functional,objectoriented</paradigm><typing>ducktyping,dynamic</typing></language><languageyear="2003"><name>Groovy</name><paradigm>functional,objectoriented</paradigm><typing>ducktyping,dynamic,static</typing></language></languages>
can be generated via the following Groovy code:
defwriter=newStringWriter()defbuilder=newgroovy.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 throughStreamingMarkupBuilder
. To change the implementation to JSON, theMarkupBuilder
can be swapped toJsonBuilder
.[33]
To parse it and search for a functional language, Groovy'sfindAll
method can serve:
deflanguages=newXmlSlurper().parseTextwriter.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.deffunctional=languages.language.findAll{it.paradigm=~"functional"}assertfunctional.collect{it.name}==["Groovy","Ruby"]
In Groovy, strings can be interpolated with variables and expressions by using GStrings:[34]
BigDecimalaccount=10.0deftext="The account shows currently a balance of $account"asserttext=="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:
BigDecimalminus=4.0text="The account shows currently a balance of ${account - minus}"asserttext=="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"asserttext=="The account shows currently a balance of 10.0 - minus"
Expression evaluation can be deferred by employing arrow syntax:
BigDecimaltax=0.15text="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:asserttext=="The account shows currently a balance of 9.000"
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."[35]
Examples of ASTs in Groovy are:
among others.
The testing frameworkSpock 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.[36] An example of such a test is:
def"maximum of #a and #b is #c"(){expect:Math.max(a,b)==cwhere:a|b||c3|5||57|0||70|0||0}
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 asinterfaces carrying both default implementations and state. A trait is defined using the trait keyword:
traitFlyingAbility{/* declaration of a trait */Stringfly(){"I'm flying!"}/* declaration of a method inside a trait */}
Then, it can be used like a normal interface using the keywordimplements
:
classBirdimplementsFlyingAbility{}/* Adds the trait FlyingAbility to the Bird class capabilities */defbird=newBird()/* instantiate a new Bird */assertbird.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.
Notable examples of Groovy adoption include:
Manyintegrated development environments (IDEs) andtext editors support Groovy:
There is one alternative implementation of Groovy: