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
falseAll 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 ClassCastExceptionThe 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() == StringIn 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() == BigIntegerGroovy uses BigDecimal for all floating-point literals and arithmetic calculations.
Floating-point values
(2.5).getClass() == java.math.BigDecimal
(2/3).getClass() == java.math.BigDecimalUnlike 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 GStringThe ${…} 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 palindromeThe ==~ 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.PatternA 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 << 100def 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 // LinkedHashMapList numsSet = [3, 1, 4, 1, 5, 9, 2, 6, 5] as Set // as SortedSet
println numsSet
println numsSet.class.nameList 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 parenthesesList 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 <=> yIn 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)
}
}
exercisesSpecial thanks to Ken Kousen