trait
FlyingAbility
{
String
fly()
{
"I'm
flying!"
}
}
! class
Bird
implements
FlyingAbility
{}
def
b
=
new
Bird()
! assert
b.fly()
==
"I'm
flying!" Traits: a simple example « trait », a new keyword for a new concept
trait
FlyingAbility
{
String
fly()
{
"I'm
flying!"
}
}
! class
Bird
implements
FlyingAbility
{}
def
b
=
new
Bird()
! assert
b.fly()
==
"I'm
flying!" Traits: a simple example a class « implements » a trait
trait
FlyingAbility
{
String
fly()
{
"I'm
flying!"
}
}
! class
Bird
implements
FlyingAbility
{}
def
b
=
new
Bird()
! assert
b.fly()
==
"I'm
flying!" Traits: a simple example the fly() method from the trait is available
trait
Named
{
String
name
}
! class
Bird
implements
Named
{}
def
b
=
new
Bird(name:
'Colibri')
! assert
b.name
==
'Colibri' Traits: stateful a Groovy property
trait
Named
{
String
name
}
! class
Bird
implements
Named
{}
def
b
=
new
Bird(name:
'Colibri')
! assert
b.name
==
'Colibri' Traits: stateful implement the trait
trait
Named
{
String
name
}
! class
Bird
implements
Named
{}
def
b
=
new
Bird(name:
'Colibri')
! assert
b.name
==
'Colibri' Traits: stateful Groovy named argument constructor
trait
Named
{
String
name
}
! class
Bird
implements
Named
{}
def
b
=
new
Bird(name:
'Colibri')
! assert
b.name
==
'Colibri' Traits: stateful access the property
trait
KiteSurfer
{
String
surf()
{
'kite'
}
}
! trait
WebSurfer
{
String
surf()
{
'web'
}
}
! class
Person
{
String
name
}
! class
Hipster
extends
Person
implements
KiteSurfer,
WebSurfer
{}
! def
h
=
new
Hipster()
assert
h.surf()
==
'web' Traits: what about conflicts? extending a class and implementing the two traits
trait
KiteSurfer
{
String
surf()
{
'kite'
}
}
! trait
WebSurfer
{
String
surf()
{
'web'
}
}
! class
Person
{
String
name
}
! class
Hipster
extends
Person
implements
WebSurfer,
KiteSurfer
{
String
surf()
{
KiteSurfer.super.surf()
}
}
! def
h
=
new
Hipster()
assert
h.surf()
==
'kite' Traits: what about conflicts? Your class method takes precedence over the traits
trait
Named
{
String
name
}
! class
Animal
{}
class
NamedAnimal
implements
Named
{}
! def
na
=
new
NamedAnimal(name:
'Felix')
! assert
na.name
==
'Felix' Traits: runtime implementation
trait
Named
{
String
name
}
! class
Animal
{}
class
NamedAnimal
implements
Named
{}
! def
na
=
new
NamedAnimal(name:
'Felix')
! assert
na.name
==
'Felix' Traits: runtime implementation Somewhat artificial to have to create an intermediary class to get named animals
trait
Named
{
String
name
}
! class
Animal
{}
class
NamedAnimal
implements
Named
{}
! def
na
=
new
NamedAnimal(name:
'Felix')
! assert
na.name
==
'Felix' Traits: runtime implementation
trait
Named
{
String
name
}
! class
Animal
{}
! ! def
na
=
new
Animal()
as
Named
na.name
=
'Felix'
assert
na.name
==
'Felix' Traits: runtime implementation
trait
Named
{
String
name
}
! class
Animal
{}
! ! def
na
=
new
Animal()
as
Named
na.name
=
'Felix'
assert
na.name
==
'Felix' Traits: runtime implementation Runtime trait, with Groovy’s usual coercion mechanism
trait
Named
{
String
name
}
! class
Animal
{}
! ! def
na
=
new
Animal()
as
Named
na.name
=
'Felix'
assert
na.name
==
'Felix' Traits: runtime implementation
New: @TailRecursive import
groovy.transform.TailRecursive
! @TailRecursive
def
fact(BigInteger
n,
accu
=
1G)
{
if
(n
<
2)
accu
else
fact(n
-‐
1,
n
*
accu)
}
! assert
fact(1000)
>
10e2566 Downside of tail recursion is you might have to rewrite your algo to be tailrec friendly
New: @Sortable import
groovy.transform.*
! @Sortable
class
Person
{
String
lastName
String
firstName
int
age
} Makes the class Comparable by multiple Comparators
New: @Sortable import
groovy.transform.*
! @Sortable
class
Person
{
String
lastName
String
firstName
int
age
} First compare by lastName, then by firstName, etc.
New: @Sortable import
groovy.transform.*
! @Sortable
class
Person
{
String
lastName
String
firstName
int
age
} You can also specify ‘includes’ / ‘excludes’ properties
@BaseScript improvements abstract
class
CustomBase
extends
Script
{
int
meaningOfLife
=
42
} @BaseScript(CustomBase)
import
groovy.transform.BaseScript
! assert
meaningOfLife
==
42 You can add your own base methods and properties to all compiled scripts
@BaseScript improvements abstract
class
CustomBase
extends
Script
{
int
meaningOfLife
=
42
} @BaseScript(CustomBase)
import
groovy.transform.BaseScript
! assert
meaningOfLife
==
42 Define the base script class for this script
@BaseScript improvements abstract
class
CustomBase
extends
Script
{
int
meaningOfLife
=
42
} @BaseScript(CustomBase)
import
groovy.transform.BaseScript
! assert
meaningOfLife
==
42 In 2.3, ability to put the annotation on imports & package
JDK 7+ NIO2 module • All the familiar methods on File retrofitted on Path as well path.withReader
{
Reader
r
-‐>
...
}
path.eachLine
{
String
line
-‐>
...
}
path.eachFileRecurse
{
Path
p
-‐>
...
}
path
<<
'some
content'
path
<<
bytes
path.readLines()
… Feature request to add all the java.nio.file.Files static utility methods as GDK
JSON parser / builder perf. increase • Re-implementation of JSON support for speed & efficiency
• parser forked off the Boon JSON project
• serializer carefully fine-tuned
! • Article on the parsing speed improvements
• http://rick-hightower.blogspot.fr/2014/04/groovy-and-boon-provide-fastest-json.html Benchmark gives 3x to 4x performance factor over Jackson and GSON
Markup template engine — the idea cars
{
cars.each
{
car(make:
it.make,
name:
it.name)
}
} model = [cars: [! new Car(make: 'Peugeot', name: '508'), ! new Car(make: 'Toyota', name: 'Prius’)! ]] Feed a model into your template
Markup template engine — static! • With typed check model creation method
! ! ! ! • Or declare your model types in the template def
modelTypes
=
[cars:
"List"]
! def
tmpl
=
engine.
createTypeCheckedModelTemplate(
"page.tpl",
modelTypes) modelTypes
=
{
List
cars
}
! cars.each
{
car
-‐>
p("Car
name:
$car.name")
} Works with createTemplate() too