class Duck {
def walk() { println "I'm a duck, I walk" }
def swim() { println "I'm a duck, I swim" }
def quack() { println "QUACK" }
}
class Person {
def walk() { println "I'm a person, I walk" }
def swim() { println "I'm a person, I swim" }
def quack() { println "QUACK, I say" }
}
def d = new Duck()
def p = new Person()
d.walk() // OK, has method
p.walk() // OK, has method
def things = ['Hello', 'Groovy', 'World']
def things = ['Hello', 'Groovy', 'World'] as Set
Set things = ['Hello', 'Groovy', 'World']
def colors = [red: 1, green: 2, blue: 3]
assert things[1] == 'Groovy'
assert things[-1] == 'World'
assert colors['red'] == 1
assert colors.green = 2
class Thing {
String name // private field, public getter and setter
int count // ditto
}
def t = new Thing()
t.name = 'Bob'
class Thing {
String name
int count
void setName(String name) { // no getter now
this.name = name
}
}
class Thing {
final String name // no setter available
Thing(String name) {
this.name = name
}
}
class Thing {
private String name // no setter unless you define it
String getName() { name }
}
def hello = { println 'hello' }
hello.call()
hello() // nicer
def printTheParam = { println it } // default is one parameter
printTheParam('hello')
printTheParam 'hello' // nicer
def printTheParam = { whatToPrint -> println whatToPrint }
def add = { int x, int y -> x + y }
def printNow = { -> println new Date() }
int i = 0
def c = { ->
println "i: $i" // can read i, in same scope as closure
i++ // can write it too
} as Clickable // has only one method, same parameter types, so coerce OK
import java.sql.Connection
def conn = [
close: { -> println 'closed' },
setAutoCommit: { boolean autoCommit -> println "$autoCommit" }
// calling undefined methods => UnsupportedOperationException
] as Connection
class SomeClass { // this class is the closure "owner", method calls go here
void callClosure() {
def dogAndCat = {
woof() // OK, in scope of closure
meow() // fail, not defined
}
dogAndCat()
}
void woof() { println 'Woof!' }
}
class Person {
String firstName
String initial
String lastName
Integer age
}
// Map constructor if no others defined, uses setters
def author = new Person(firstName: 'Hunter', initial: 'S', lastName: 'Thompson')
def in = new FileInputStream('file.txt') // try-catch of checked exceptions optional
if (nullobject) { println 'null == false' }
if (collectionNonEmpty) { println 'non-empty collection == true' }
if (arrayNonEmpty) { println 'ditto' }
if (mapNonEmpty) { println 'ditto' }
if (iter) { println 'iterator with stuff left == true' }
if (enumer) { println 'ditto' }
if (regex) { println 'matching regex pattern == true' }
if ("non-zero") { println 'true' }
if (1234) { println 'non-zero == true' }
if ('c') { println 'ditto' }
Semicolons are optional!
def easyReturn { 'return this string' }
def PublicClass {
String publicField
int publicMethod { 42 }
} // private and protected still OK, use @PackageScope for that
println "parens optional except when no args"
def catted = StringUtils.concat("or when", "on RHS of assignment")
Auto-imports: java.lang, .io, .util, .net, groovy.lang, .util, BigDecimal, BigInteger
String[] init = ['cannot', 'use', 'curly braces']
def init2 = ['must', 'define', 'list', 'and', 'cast'] as String[]
@Annotation(['same', 'for', 'annotation', 'array', 'values'])
for (bar in bars) { println 'in is a keyword' }
def warning = { println 'and so is def!' }
There is no do-while loop!
int count = someCalc()
for (int i = 0; i < count; i++) {
println "Cannot initialize multiple variables in start of for loop")
}
someCalc().times { println "or just do this" }
for (i in 0..someCalc() - 1) { println "or this" }
assert result == "this" // on objects, it's overloaded to call .equals
assert oneObject.is(sameObject) // replaces ==
assert result?.equals("this") // same overload
Object connection = createConnection()
connection.close() // in Java, calls for Object always; in Groovy, calls based on runtime type
println 'Single quote strings are fine'
println '''Multi-line
works
too'''
def fullName = "$person.firstName ${person.initial ? person.initial + ' ' : ''}$person.lastName" // GString
println """$person.firstName
$person.lastName""" // double-quote multi-line
String str = 'Groovy Strings are groovy'
assert str[4] == 'v' // 'v' is a string here, not a char
assert str[0..5] == 'Groovy'
assert str[19..-1] == 'groovy'
assert str[15..17] == 'are'
assert str[17..15] == 'era'
private static final Logger LOGGER = Logger.getLogger(this) // class!
Object invokeMethod(String name, Object args)
Object getProperty(String property)
void setProperty(String property, Object newValue)
MetaClass getMetaClass()
void setMetaClass(MetaClass metaClass)
List.metaClass.removeRight = { int index ->
delegate.remove(delegate.size() - 1 - index)
// delegate is the instance that the closure is invoked on
}
class MathUtils {
int add(int i, int j) { i + j }
def invokeMethod(String name, Object args) {
println "Undefined method $name"
}
}
class Person {
private String name // no getters or setters outside class
def getProperty(String property) {
if ('name'.equals(property)) {
return this.name
}
} // now p.name works
def setProperty(String property, Object newValue) {
if ('name'.equals(property)) {
this.name = newValue
}
} // now p.name = 'you' works
}
class Person {
String name
def propertyMissing(String property) {
if ('eman'.equals(property)) {
return name.reverse()
}
throw new MissingPropertyException(property, getClass())
} // also $static_propertyMissing
def methodMissing(String methodName, args) {
if ('knight'.equals(methodName)) {
name = 'Sir ' + name
return
}
throw new MissingMethodException(methodName, getClass(), args)
} // also $static_methodMissing, which will also look for closures
}
String name = person?.organization?.parent?.name // totally null-safe
String name = person.name ?: defaultName // abbreviated "Elvis"
def numbers = [1.4, 2.7, 3.1]
assert [1, 2, 3] == numbers*.intValue() // call across collection "spread"
println (lastName <=> p?.lastName) // -1, 0, or 1 "spaceship"
println p.@name // direct field access, bypass getter
def things = ['a', 'b', 'b', 'c'] as Set // type coercion
assert 1 in [1, 2, 5] // shortcut for Collection.contains
def addMethod = new MathUtils().&add // method reference => closure
class Person {
String name
List children = []
def leftShift(Person child) {
children << child
this // overload methods must return this
}
}
def parent = new Person()
def child = new Person()
parent.children.add child // or parent.children << child, neato
parent << child // there's the overload