Groovy is a dynamic language for the Java platform
1/*
2 Set yourself up:
3
4 1) Install SDKMAN - http://sdkman.io/
5 2) Install Groovy: sdk install groovy
6 3) Start the groovy console by typing: groovyConsole
7
8*/
9
10// Single line comments start with two forward slashes
11/*
12Multi line comments look like this.
13*/
14
15// Hello World
16println "Hello world!"
17
18/*
19 Variables:
20
21 You can assign values to variables for later use
22*/
23
24def x = 1
25println x
26
27x = new java.util.Date()
28println x
29
30x = -3.1499392
31println x
32
33x = false
34println x
35
36x = "Groovy!"
37println x
38
39/*
40 Collections and maps
41*/
42
43//Creating an empty list
44def technologies = []
45
46// or create a list with data
47technologies = ["Kotlin", "Swift"]
48
49/*** Adding a elements to the list ***/
50
51// As with Java
52technologies.add("Grails")
53
54// Left shift adds, and returns the list
55technologies << "Groovy"
56
57// Add multiple elements
58technologies.addAll(["Gradle","Griffon"])
59
60/*** Removing elements from the list ***/
61
62// As with Java
63technologies.remove("Griffon")
64
65// Subtraction works also
66technologies = technologies - 'Grails'
67
68/*** Iterating Lists ***/
69
70// Iterate over elements of a list
71technologies.each { println "Technology: $it"}
72technologies.eachWithIndex { it, i -> println "$i: $it"}
73
74/*** Checking List contents ***/
75
76//Evaluate if a list contains element(s) (boolean)
77contained = technologies.contains( 'Groovy' )
78
79// Or
80contained = 'Groovy' in technologies
81
82// Check for multiple contents
83technologies.containsAll(['Groovy','Grails'])
84
85/*** Sorting Lists ***/
86
87// Sort a list (mutates original list)
88technologies.sort()
89
90// To sort without mutating original, you can do:
91sortedTechnologies = technologies.sort( false )
92
93/*** Manipulating Lists ***/
94
95//Replace all elements in the list
96Collections.replaceAll(technologies, 'Gradle', 'gradle')
97
98//Shuffle a list
99Collections.shuffle(technologies, new Random())
100
101//Clear a list
102technologies.clear()
103
104//Creating an empty map
105def devMap = [:]
106
107//Add values
108devMap = ['name':'Roberto', 'framework':'Grails', 'language':'Groovy']
109devMap.put('lastName','Perez')
110
111//Iterate over elements of a map
112devMap.each { println "$it.key: $it.value" }
113devMap.eachWithIndex { it, i -> println "$i: $it"}
114
115//Evaluate if a map contains a key
116assert devMap.containsKey('name')
117
118//Evaluate if a map contains a value
119assert devMap.containsValue('Roberto')
120
121//Get the keys of a map
122println devMap.keySet()
123
124//Get the values of a map
125println devMap.values()
126
127/*
128 Groovy Beans
129
130 GroovyBeans are JavaBeans but using a much simpler syntax
131
132 When Groovy is compiled to bytecode, the following rules are used.
133
134 * If the name is declared with an access modifier (public, private or
135 protected) then a field is generated.
136
137 * A name declared with no access modifier generates a private field with
138 public getter and setter (i.e. a property).
139
140 * If a property is declared final the private field is created final and no
141 setter is generated.
142
143 * You can declare a property and also declare your own getter or setter.
144
145 * You can declare a property and a field of the same name, the property will
146 use that field then.
147
148 * If you want a private or protected property you have to provide your own
149 getter and setter which must be declared private or protected.
150
151 * If you access a property from within the class the property is defined in
152 at compile time with implicit or explicit this (for example this.foo, or
153 simply foo), Groovy will access the field directly instead of going though
154 the getter and setter.
155
156 * If you access a property that does not exist using the explicit or
157 implicit foo, then Groovy will access the property through the meta class,
158 which may fail at runtime.
159
160*/
161
162class Foo {
163 // read only property
164 final String name = "Roberto"
165
166 // read only property with public getter and protected setter
167 String language
168 protected void setLanguage(String language) { this.language = language }
169
170 // dynamically typed property
171 def lastName
172}
173
174/*
175 Methods with optional parameters
176*/
177
178// A method can have default values for parameters
179def say(msg = 'Hello', name = 'world') {
180 "$msg $name!"
181}
182
183// It can be called in 3 different ways
184assert 'Hello world!' == say()
185// Right most parameter with default value is eliminated first.
186assert 'Hi world!' == say('Hi')
187assert 'learn groovy!' == say('learn', 'groovy')
188
189/*
190 Logical Branching and Looping
191*/
192
193//Groovy supports the usual if - else syntax
194def x = 3
195
196if(x==1) {
197 println "One"
198} else if(x==2) {
199 println "Two"
200} else {
201 println "X greater than Two"
202}
203
204//Groovy also supports the ternary operator:
205def y = 10
206def x = (y > 1) ? "worked" : "failed"
207assert x == "worked"
208
209//Groovy supports 'The Elvis Operator' too!
210//Instead of using the ternary operator:
211
212displayName = user.name ? user.name : 'Anonymous'
213
214//We can write it:
215displayName = user.name ?: 'Anonymous'
216
217//For loop
218//Iterate over a range
219def x = 0
220for (i in 0 .. 30) {
221 x += i
222}
223
224//Iterate over a list
225x = 0
226for( i in [5,3,2,1] ) {
227 x += i
228}
229
230//Iterate over an array
231array = (0..20).toArray()
232x = 0
233for (i in array) {
234 x += i
235}
236
237//Iterate over a map
238def map = ['name':'Roberto', 'framework':'Grails', 'language':'Groovy']
239x = ""
240for ( e in map ) {
241 x += e.value
242 x += " "
243}
244assert x.equals("Roberto Grails Groovy ")
245
246/*
247 Operators
248
249 Operator Overloading for a list of the common operators that Groovy supports:
250 http://www.groovy-lang.org/operators.html#Operator-Overloading
251
252 Helpful groovy operators
253*/
254//Spread operator: invoke an action on all items of an aggregate object.
255def technologies = ['Groovy','Grails','Gradle']
256technologies*.toUpperCase() // = to technologies.collect { it?.toUpperCase() }
257
258//Safe navigation operator: used to avoid a NullPointerException.
259def user = User.get(1)
260def username = user?.username
261
262
263/*
264 Closures
265 A Groovy Closure is like a "code block" or a method pointer. It is a piece of
266 code that is defined and then executed at a later point.
267
268 More info at: http://www.groovy-lang.org/closures.html
269*/
270//Example:
271def clos = { println "Hello World!" }
272
273println "Executing the Closure:"
274clos()
275
276//Passing parameters to a closure
277def sum = { a, b -> println a+b }
278sum(2,4)
279
280//Closures may refer to variables not listed in their parameter list.
281def x = 5
282def multiplyBy = { num -> num * x }
283println multiplyBy(10)
284
285// If you have a Closure that takes a single argument, you may omit the
286// parameter definition of the Closure
287def clos = { print it }
288clos( "hi" )
289
290/*
291 Groovy can memoize closure results
292*/
293def cl = {a, b ->
294 sleep(3000) // simulate some time consuming processing
295 a + b
296}
297
298mem = cl.memoize()
299
300def callClosure(a, b) {
301 def start = System.currentTimeMillis()
302 mem(a, b)
303 println "Inputs(a = $a, b = $b) - took ${System.currentTimeMillis() - start} msecs."
304}
305
306callClosure(1, 2)
307callClosure(1, 2)
308callClosure(2, 3)
309callClosure(2, 3)
310callClosure(3, 4)
311callClosure(3, 4)
312callClosure(1, 2)
313callClosure(2, 3)
314callClosure(3, 4)
315
316/*
317 Expando
318
319 The Expando class is a dynamic bean so we can add properties and we can add
320 closures as methods to an instance of this class
321
322 http://mrhaki.blogspot.mx/2009/10/groovy-goodness-expando-as-dynamic-bean.html
323*/
324 def user = new Expando(name:"Roberto")
325 assert 'Roberto' == user.name
326
327 user.lastName = 'Pérez'
328 assert 'Pérez' == user.lastName
329
330 user.showInfo = { out ->
331 out << "Name: $name"
332 out << ", Last name: $lastName"
333 }
334
335 def sw = new StringWriter()
336 println user.showInfo(sw)
337
338
339/*
340 Metaprogramming (MOP)
341*/
342
343//Using ExpandoMetaClass to add behaviour
344String.metaClass.testAdd = {
345 println "we added this"
346}
347
348String x = "test"
349x?.testAdd()
350
351//Intercepting method calls
352class Test implements GroovyInterceptable {
353 def sum(Integer x, Integer y) { x + y }
354
355 def invokeMethod(String name, args) {
356 System.out.println "Invoke method $name with args: $args"
357 }
358}
359
360def test = new Test()
361test?.sum(2,3)
362test?.multiply(2,3)
363
364//Groovy supports propertyMissing for dealing with property resolution attempts.
365class Foo {
366 def propertyMissing(String name) { name }
367}
368def f = new Foo()
369
370assertEquals "boo", f.boo
371
372/*
373 TypeChecked and CompileStatic
374 Groovy, by nature, is and will always be a dynamic language but it supports
375 typechecked and compilestatic
376
377 More info: http://www.infoq.com/articles/new-groovy-20
378*/
379//TypeChecked
380import groovy.transform.TypeChecked
381
382void testMethod() {}
383
384@TypeChecked
385void test() {
386 testMeethod()
387
388 def name = "Roberto"
389
390 println naameee
391
392}
393
394//Another example:
395import groovy.transform.TypeChecked
396
397@TypeChecked
398Integer test() {
399 Integer num = "1"
400
401 Integer[] numbers = [1,2,3,4]
402
403 Date date = numbers[1]
404
405 return "Test"
406
407}
408
409//CompileStatic example:
410import groovy.transform.CompileStatic
411
412@CompileStatic
413int sum(int x, int y) {
414 x + y
415}
416
417assert sum(2,5) == 7
Further resources ¶
Join a Groovy user group