Groovy - ilya-khadykin/notes-outdated GitHub Wiki
Prerequisite: JDK should be already installed
Download applicable distribution from http://groovy-lang.org/download.html
And set GROOVY_HOME
environment variable accordingly
You can also use Groovy enVironment Manager (UNIX)
You can compile it with groovyc
compiler or you can also run scripts without compiling in groovysh
void sayHello(String name) {
println "Hello, ${name}!"
}
sayHello('Dolly')
-
groovyc
- compiler
> groovyc hello_world.groovy // creates hello_world.class
NOTE: The Groovy compiler knows how to compile Java, too -
groovy
- command for running Groovy code
> groovy -e 'println InetAddress.localHost' // prints name and IP address of host system
groovy hello_world.groovy
-
groovysh
- groovy shell -
groovyConsole
- a simple IDE distributed with the language (something similar to Python`s IDLE)
- last evaluated expression is always returned by default, no return needed
String toString() {
"$classField1 $classField2"
}
- if closure is the last parameter of a method you can specify it outside of parentheses
10.downto(7) { println it }
In Java, if you don’t add any import statements you get java.lang.*
automatically.
In Groovy, if you don’t add any import statements, you get:
java.lang.*
java.util.*
java.net.*
java.io.*
java.math.BigInteger
java.math.BigDecimal
groovy.lang.*
groovy.util.*
Groovy classes therefore have far fewer import statements than Java classes.
In Java, the only overloaded operator is +
, which means addition for numerical values and concatenation for strings.
In Groovy, all operators invoke methods. The complete list of operators is given on http://groovy.codehaus.org/Operator+Overloading. Here is an abbreviated version.
Table with Operators and Corresponding Methods
Operator | Method call |
---|---|
a + b |
a.plus(b) |
a - b |
a.minus(b) |
a * b |
a.multiply(b) |
a / b |
a.div(b) |
a % b |
a.mod(b) |
a ** b |
a.power(b) |
a++ |
a.next() |
a-- |
a.previous() |
a[b] |
a.getAt(b) |
a[b] = c |
a.putAt(b, c) a == b a.equals(b) or a.compareTo(b) == 0 |
While overloading operators in regular Groovy programs is not that common, it’s used throughout the standard libraries.
For example, the java.lang.Number
class is the superclass of all the wrapper classes as well as java.math.BigInteger
and java.math.BigDecimal
. The Groovy JDK adds plus, minus, and others to Number
, which allows the operators to be used with all of its subclasses.
Java has an assert
keyword that is rarely used and turned off by default.
Groovy uses a "power assert" that returns a lot of information when it fails
int x = 3
int y = 4
assert 7 == x + y // true, so returns nothing
assert 7 == x + y + 1
Assertion failed:
assert 7 == x + y + 1
| | | | |
| 3 7 4 8
false
All that extra debugging information means most Groovy developers use assert
in all their tests
Groovy is optionally typed. If you declare a variable to be of type String
, or Date
, or Employee
, then that’s all that can be assigned to them.
Integer x = 1
x = 'abc' // throws ClassCastException
The def
keyword tells the compiler we are not declaring a type, which will be determined at runtime.
def x = 1
assert x.getClass() == Integer
x = new Date()
assert x.getClass() == Date
x = 'abc'
assert x.getClass() == String
In Grails, properties in domain classes — which are mapped to database tables — require actual data types. The def
keyword is often used as the return type on controller methods, however.
Groovy uses the same numeric types as Java, but there are no primitives in Groovy. Instead, Groovy uses the wrapper classes (like Integer
, Double
, and Boolean
) for any primitive values.
The default type for a non-floating point literal is Integer
or longer:
Non-floating point literals
assert 3.getClass() == Integer
assert 33333333333333.getClass() == Long
assert 33333333333333333333333.getClass() == BigInteger
Groovy uses BigDecimal
for all floating-point literals and arithmetic calculations.
Floating-point values
(2.5).getClass() == java.math.BigDecimal
(2/3).getClass() == java.math.BigDecimal
Unlike Java, division is done at BigDecimal
levels even if both arguments are integers. If you want integer division, use the intdiv
method in java.lang.Number
.
Groovy has two types of strings, single- and double-quoted:
- Single-quoted strings are instances of
java.lang.String
. - Double-quoted strings are Groovy strings and allow interpolation:
def s = 'this is a string'
assert s.getClass() == String
s = "this uses double-quotes but is still a String"
assert s.getClass() == String
s = "this string uses interpolation: ${1 + 1}"
assert s == 'this string uses interpolation: 2'
assert s instanceof GString
The ${…}
notation inside a double-quoted string evaluates its contents as a Groovy expression and invokes toString
on the result.
If you are evaluating a variable only, you can leave out the braces.
String first = 'Graeme'
String last = 'Rocher'
assert "$first $last" == 'Graeme Rocher'
Groovy also supports multiline strings. Three single quotes are regular multiline strings.
def picard = '''
Oh the vaccuum outside is endless
Unforgiving, cold, and friendless
But still we must boldly go
Make it so, make it so, make it so!
'''
This string has five lines, because the first line starts with a carriage return.
Three double-quotes are multiline Groovy strings.
```groovy
def saying = """
There are ${Integer.toBinaryString(2)} kinds of people in the world
Those who know binary, and those who don't
"""
Multiline strings are helpful in many situations, but they are particularly useful when executing SQL statements.
Finally, Groovy supports what are called _slashy_ strings, which are delimited by forward slashes.
__Slashy strings for regular expressions__
```groovy
def zip = /\d{5}(-\d{4})?/
assert '12345' ==~ zip
assert '12345-1234' ==~
zip assert '12345 12345-1234 1234'.findAll(zip) ==
['12345', '12345-1234']
Slashy strings do not require you to use double backslashes inside regular expressions. Here the \d
pattern represents a decimal digit. The pattern \W
means any non-word character (i.e., other than [azA-Z0-9_]
).
def testString = 'Flee to me, remote elf!'.toLowerCase().replaceAll(/\W/,'')
assert testString == 'fleetomeremoteelf'
assert testString == testString.reverse() // test string is a palindrome
The ==~
operator checks for an exact match and returns the boolean
true or false.
The =~
operator returns an instance of java.util.regex.Matcher
.
Using a tilde on a slashy string turns it into an instance of java.util.regex.Pattern
, as in
assert ~/abcd/ instanceof java.util.regex.Pattern
A more detailed discussion of regular expressions in Groovy can be found at http://groovy.codehaus.org/Regular+Expressions.
import groovy.transform.*
@EqualsAndHashCode // Groovy Annotation generates .equals() and .hashCode()
@TupleConstructor
//@Cannonical generates toString(), equals(), hashCode() and tuple constructor
class Person {
String first
String last
String toString() { "$first $last" }
}
Person p = new Person()
p.setFirst('David')
p.last = 'Ortiz' // calls setter method, does not violates encapsulation
println "${p.getFirst()} ${p.last}"
Person pConstructor = new Person(first: 'Name', last: 'Surname') // calls setters using provided Map
println pConstructor.toString()
for (n in nums) {
println n // def is assumed
}
Range r = 1..10
println(r)
println r.from
println r.to
print r.contains(10)
r = 1..<10
println(r)
List nums = [3, 1, 4, 1, 5, 9, 2, 6, 5]
List numsLinkedList = [3, 1, 4, 1, 5, 9, 2, 6, 5] as LinkedList
println nums
println nums.class.name
nums -1 -5
nums * 2
nums + [3, 5]
nums << 100
def map = [a:1, b:2, c:2]
map.put('d', 3)
map['e'] = 1
println map
println map.class.name // throws Exception since dot '.' operator has been already overloaded
println map.getClass().name // LinkedHashMap
List numsSet = [3, 1, 4, 1, 5, 9, 2, 6, 5] as Set // as SortedSet
println numsSet
println numsSet.class.name
List nums = [3, 1, 4, 1, 5, 9]
nums.each {
println it // 'it' is a default name for a parameter
}
nums.each { n ->
println n
}
nums.eachWithIndex { n, idx ->
println "nums[$idx] == $n"
}
Map m = [a:1, b:2, c:2]
m.each { e ->
println "m[${e.key}] == ${e.value}"
}
m.each { k, v ->
println "m[$k] == $v"
}
10.downto(7, { println it } ) // Java style
10.downto(7) { println it } // Idiomatic Groovy
10.downto 7, { println it } // optional parentheses
List nums = [1, 2, 64, 4, 3]
nums.collect { it * 2 } // map
.findAll { it % 3 == 0 } // filter
.sun() //reduce
*.
applies to every element of the collection
List strings = 'this is a list of strings'.split()
prinln strings.collect { it.size() }
println strings*.size() // equivalent to strings.collect wit closure
println strings.size()
?.
returns null if some property is null and does not throw NullPointerException
int x = 3
int y = 6
int z = 8
println x <=> y // invokes compareTo()
println y <=> y
println z <=> y
In Groovy, all the following are true:
- Non-zero numbers
- Non-null references
- Non-empty strings
- Non-empty collections
- Regular expressions with a match
- Boolean true
String name
String n = (name != null && name.size() > 0 ? name: 'World')
n = name ? name : 'World'
n = name ?: 'World' // equivalent to the above
println "Hello, %n!"
Here is an example of how to do it (copied from groovyConsole
):
import groovy.json.JsonSlurper
def jsonSlurper = new JsonSlurper()
def contents = jsonSlurper.parseText('https://raw.githubusercontent.com/exercism/java/master/config.json'.toURL().text)
def exercises = []
contents.exercises.each{
if (!it.deprecated) {
exercises.add(it.slug)
}
}
exercises
Special thanks to Ken Kousen