Groovy uses a similar syntax to Java although in Groovy semicolons are optional.
This saves a little typing but also makes code look much cleaner (surprisingly so for such a minor change). So normally if one statement is on each line you can ommit semicolons altogether - though its no problem to use them if you want to. If you want to put multiple statements on a line use a semicolon to separate the statements.
| Code Block |
|---|
|
def x = [1, 2, 3]
println x
def y = 5; def x = y + 7
println x
assert x == 12
|
If the end of the line is reached and the current statement is not yet complete it can be spanned across multiple lines. So for things like method parameters or creating lists or for complex if expressions you can span multiple lines.
| Code Block |
|---|
|
def x = [1, 2, 3,
4, 5, 6]
println(
x
)
if (x != null &&
x.size() > 5) {
println("Works!")
}
else {
assert false: "should never happen ${x}"
}
|
...
In Groovy 1.6, there is only one syntax addition for being able to define and assign several variables at once:
| Code Block |
|---|
def (a, b) = [1, 2]
assert a == 1
assert b == 2
|
A more meaninful example may be methods returning longitute and latitude coordinates. If these coordinates are represented as a list of two elements, you can easily get back to each element as follows:
| Code Block |
|---|
def geocode(String location) {
// implementation returns [48.824068, 2.531733] for Paris, France
[48.824068, 2.531733]
}
def (lat, longlon) = geocode("Paris, France")
assert lat == 48.824068
assert longlon == 2.531733
|
And you can also define the types of the variables in one shot as follows:
| Code Block |
|---|
def (int i, String s) = [1, 'Groovy']
assert i == 1
assert s == 'Groovy'
|
For the assignment (with prior definition of the variables), just omit the def keyword:
| Code Block |
|---|
def firstname, lastname
(firstname, lastname) = "Guillaume Laforge".tokenize()
assert firstname == "Guillaume"
assert lastname == "Laforge"
|
...
So for the case with more variables than list elements, here, c will be null:
| Code Block |
|---|
def elements = [1, 2]
def (a, b, c) = elements
assert a == 1
assert b == 2
assert c == null
|
Whereas in the case where there are more list elements than variables, we'll get the following expectations:
| Code Block |
|---|
def elements = [1, 2, 3, 4]
def (a, b, c) = elements
assert a == 1
assert b == 2
assert c == 3
|
For the curious minds, supporting multiple assignments also means we can do the standard school swap case in one line:
| Code Block |
|---|
// given those two variables
def a = 1, b = 2
// swap variables with a list
(a, b) = [b, a]
assert a == 2
assert b == 1
|
...
The characters "//" begin a comment that last for the rest of the line.
| Code Block |
|---|
|
print "hello" // This is a silly print statement
|
The characters "/*" begin a comment that lasts until the first "*/".
| Code Block |
|---|
|
/* This is a long comment
about our favorite println */
println "hello"
|
The character "#" is not a comment character.
| Code Block |
|---|
|
// This doesn't work:
# Bad comment
|
...
Method calling syntax is similar to Java where methods can be called on an object (using dot) or a method on the current class can be called. Static and instance methods are supported.
| Code Block |
|---|
|
class Foo {
def calculatePrice() {
1.23
}
static void main(args) {
def foo = new Foo()
def p = foo.calculatePrice()
assert p > 0
println "Found price: " + p
}
}
|
...
Method calls in Groovy can omit the parenthesis if there is at least one parameter and there is no ambiguity.
| Code Block |
|---|
|
println "Hello world"
System.out.println "Nice cheese Gromit!"
|
It is also possible to omit parenthesis when using named arguments. This makes for nicer DSLs:
| Code Block |
|---|
compare fund: "SuperInvestment", withBench: "NIKEI"
monster.move from: [3,4], to: [4,5]
|
...
Currently this kind of method passing is only implemented for calling methods which take a Map or for constructing JavaBeans.
| Code Block |
|---|
|
def bean = new Expando(name:"James", location:"London", id:123)
println "Hey " + bean.name
assert bean.id == 123
|
...
Closures are described in more detail
| Wiki Markup |
|---|
{link:here|closures}{link} |
.
Closures can be passed into methods like any other object
| Code Block |
|---|
|
def closure = { param -> param + 1 }
def answer = [1, 2].collect(closure)
assert answer == [2, 3]
|
Though there is some syntax sugar to make calling methods which take a closure easier. Instead of specifying parenthesis, you can just specify a closure. e.g.
| Code Block |
|---|
|
answer = [1, 2].collect { param -> param + 1 }
assert answer == [2, 3]
|
The above code is equivalent to the previous code, just a little more groovy. If a method takes parameters you can leave the closure outside of the parenthesis (provided that the closure parameter is the last parameter on the underlying method).
| Code Block |
|---|
|
def value = [1, 2, 3].inject(0) { count, item -> count + item }
assert value == 6
|
The above code is equivalent to the following (but just neater)
| Code Block |
|---|
|
def value = [1, 2, 3].inject(0, { count, item -> count + item })
assert value == 6
|
...
Groovy always uses dynamic dispatch, even if a variable is constrained by a type. The type of the variable only ensures that the variable is at least of that type and avoids you assigning a String to for example int. Dynamic method dispatch is often referred to as dynamic typing whereas Java uses static typing by default.
| Code Block |
|---|
|
def dynamicObject = "hello world".replaceAll("world", "Gromit")
dynamicObject += "!"
assert dynamicObject == "hello Gromit!"
String staticObject = "hello there"
staticObject += "!"
assert staticObject == "hello there!"
|
...
These are described in more detail in the Groovy Beans section.
To access properties you use dot with the property name. e.g.
| Code Block |
|---|
|
def bean = new Expando(name:"James", location:"London", id:123)
def name = bean.name
println("Hey ${name}")
bean.location = "Vegas"
println bean.name + " is now in " + bean.location
assert bean.location == "Vegas"
|
...
If you are walking a complex object graph and don't want to have NullPointerExceptions thrown you can use the ?. operator rather than . to perform your navigation.
| Code Block |
|---|
|
def foo = null
def bar = foo?.something?.myMethod()
assert bar == null
|