SlideShare uma empresa Scribd logo
1 de 255
Baixar para ler offline
What makes
Groovy groovy?
Guillaume Laforge 

@glaforge
Guillaume
Laforge
Groovy project lead
at
.
!

@glaforge
http://glaforge.appspot.com
What makes Groovy Groovy  - Guillaume Laforge (Pivotal)
1
t
r
a
P

The Groovy
vision
What makes Groovy Groovy  - Guillaume Laforge (Pivotal)
Simplify the life of
(Java) developers
What makes Groovy Groovy  - Guillaume Laforge (Pivotal)
Groovy as a
Java superset
Groovy as a
Java superset

It’s so easy
to learn!
What makes Groovy Groovy  - Guillaume Laforge (Pivotal)
What makes Groovy Groovy  - Guillaume Laforge (Pivotal)
What makes Groovy Groovy  - Guillaume Laforge (Pivotal)
class	
  MathSpec	
  extends	
  Specification	
  {	
  
	
  	
  	
  	
  def	
  "maximum	
  of	
  two	
  numbers"()	
  {	
  
	
  	
  	
  	
  	
  	
  expect:	
  
	
  	
  	
  	
  	
  	
  	
  	
  Math.max(a,	
  b)	
  ==	
  c	
  
!

	
  	
  	
  	
  	
  	
  where:	
  
	
  	
  	
  	
  	
  	
  	
  	
  a	
  |	
  b	
  ||	
  c	
  
	
  	
  	
  	
  	
  	
  	
  	
  1	
  |	
  3	
  ||	
  3	
  
	
  	
  	
  	
  	
  	
  	
  	
  7	
  |	
  4	
  ||	
  4	
  
	
  	
  	
  	
  	
  	
  	
  	
  0	
  |	
  0	
  ||	
  0	
  
	
  	
  	
  	
  }	
  
}
What makes Groovy Groovy  - Guillaume Laforge (Pivotal)
As safe and fast as Java with
static type checking & compilation
As safe and fast as Java with
static type checking & compilation
What makes Groovy Groovy  - Guillaume Laforge (Pivotal)
new	
  MarkupBuilder().html	
  {	
  
	
  	
  	
  	
  head	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  title	
  "The	
  Script	
  Bowl"	
  
	
  	
  	
  	
  }	
  
!

	
  	
  	
  	
  body	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  div(class:	
  "banner")	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  p	
  "Groovy	
  rocks!"	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  }	
  
}
What makes Groovy Groovy  - Guillaume Laforge (Pivotal)
move	
  forward	
  at	
  3.km/h
Expressive,
Concise,
Readable
What makes Groovy Groovy  - Guillaume Laforge (Pivotal)
What makes Groovy Groovy  - Guillaume Laforge (Pivotal)
Speaking of conciseness...
A full Spring app in the span of a tweet!
@RestController	
  
class	
  App	
  {	
  
	
  	
  	
  	
  @RequestMapping("/")	
  
	
  	
  	
  	
  String	
  home()	
  {	
  "Hello	
  World!"	
  }	
  
}
1.7

million 

downloads

per year
What makes Groovy Groovy  - Guillaume Laforge (Pivotal)
Great for
scripting
Great for
scripting

Fit for DomainSpecific Languages
Great for
scripting

Fit for DomainSpecific Languages

Most seamless integration &
interoperability wih java!
What makes Groovy Groovy  - Guillaume Laforge (Pivotal)
What makes Groovy Groovy  - Guillaume Laforge (Pivotal)
Yup, we’re all
using Groovy!
2
t
r
a
P

Cool Groovy
gems
What makes Groovy Groovy  - Guillaume Laforge (Pivotal)
Most Java code is also
valid Groovy code!
Most Java code is also
valid Groovy code!

Any Java developer is a
Groovy developer!
What makes Groovy Groovy  - Guillaume Laforge (Pivotal)
Flat learning
curve
Flat learning
curve

Easy to learn
Scripts versus Classes
public	
  class	
  Main	
  {	
  
	
  	
  	
  	
  public	
  static	
  void	
  main(String[]	
  args)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  System.out.println("Hello");	
  
	
  	
  	
  	
  }	
  
}

vs
!18
Scripts versus Classes
public	
  class	
  Main	
  {	
  
	
  	
  	
  	
  public	
  static	
  void	
  main(String[]	
  args)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  System.out.println("Hello");	
  
	
  	
  	
  	
  }	
  
}

vs
println	
  "Hello"
!18
Optional
Semicolons

Optional
Semicolons
Parentheses

Optional
Semicolons
Parentheses

Optional
return keyword
Semicolons
Parentheses

Optional
return keyword

public keyword
Semicolons
Parentheses

Optional
Typing!
return keyword

public keyword
Optional...
public	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  private	
  String	
  owner;	
  
!
	
  	
  	
  	
  public	
  String	
  getOwner()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  owner;	
  
	
  	
  	
  	
  }	
  
!
	
  	
  	
  	
  public	
  void	
  setOwner(String	
  owner)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  this.owner	
  =	
  owner;	
  
	
  	
  	
  	
  }	
  
!
	
  	
  	
  	
  public	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  "Hello	
  "	
  +	
  name	
  +	
  ",	
  I	
  am	
  "	
  +	
  owner;	
  
	
  	
  	
  	
  }	
  
}	
  
!
Greeter	
  greeter	
  =	
  new	
  Greeter();	
  
greeter.setOwner("Guillaume");	
  
!
System.out.println(greeter.greet("Marion"));
!20
Optional...

Semicolons

public	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  private	
  String	
  owner;	
  
!
	
  	
  	
  	
  public	
  String	
  getOwner()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  owner;	
  
	
  	
  	
  	
  }	
  
!
	
  	
  	
  	
  public	
  void	
  setOwner(String	
  owner)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  this.owner	
  =	
  owner;	
  
	
  	
  	
  	
  }	
  
!
	
  	
  	
  	
  public	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  "Hello	
  "	
  +	
  name	
  +	
  ",	
  I	
  am	
  "	
  +	
  owner;	
  
	
  	
  	
  	
  }	
  
}	
  
!
Greeter	
  greeter	
  =	
  new	
  Greeter();	
  
greeter.setOwner("Guillaume");	
  
!
System.out.println(greeter.greet("Marion"));
!20
Optional...
public	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  private	
  String	
  owner	
  
!
	
  	
  	
  	
  public	
  String	
  getOwner()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  owner	
  
	
  	
  	
  	
  }	
  
!
	
  	
  	
  	
  public	
  void	
  setOwner(String	
  owner)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  this.owner	
  =	
  owner	
  
	
  	
  	
  	
  }	
  
!
	
  	
  	
  	
  public	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  "Hello	
  "	
  +	
  name	
  +	
  ",	
  I	
  am	
  "	
  +	
  owner	
  
	
  	
  	
  	
  }	
  
}	
  
!
Greeter	
  greeter	
  =	
  new	
  Greeter()	
  
greeter.setOwner("Guillaume")	
  
!
System.out.println(greeter.greet("Marion"))
!21
Optional...
public	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  private	
  String	
  owner	
  
!
	
  	
  	
  	
  public	
  String	
  getOwner()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  owner	
  
	
  	
  	
  	
  }	
  
!
	
  	
  	
  	
  public	
  void	
  setOwner(String	
  owner)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  this.owner	
  =	
  owner	
  
	
  	
  	
  	
  }	
  
!
	
  	
  	
  	
  public	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  "Hello	
  "	
  +	
  name	
  +	
  ",	
  I	
  am	
  "	
  +	
  owner	
  
	
  	
  	
  	
  }	
  
}	
  
!
Greeter	
  greeter	
  =	
  new	
  Greeter()	
  
greeter.setOwner("Guillaume")	
  
!
System.out.println(greeter.greet("Marion"))
!22
Optional...
public	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  private	
  String	
  owner	
  
!
	
  	
  	
  	
  public	
  String	
  getOwner()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  owner	
  
	
  	
  	
  	
  }	
  
!
	
  	
  	
  	
  public	
  void	
  setOwner(String	
  owner)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  this.owner	
  =	
  owner	
  
	
  	
  	
  	
  }	
  
!
	
  	
  	
  	
  public	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  "Hello	
  "	
  +	
  name	
  +	
  ",	
  I	
  am	
  "	
  +	
  owner	
  
	
  	
  	
  	
  }	
  
}	
  
!
Greeter	
  greeter	
  =	
  new	
  Greeter()	
  
greeter.setOwner("Guillaume")	
  
!
System.out.println(greeter.greet("Marion"))

Parentheses

!22
Optional...
public	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  private	
  String	
  owner	
  
!
	
  	
  	
  	
  public	
  String	
  getOwner()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  owner	
  
	
  	
  	
  	
  }	
  
!
	
  	
  	
  	
  public	
  void	
  setOwner(String	
  owner)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  this.owner	
  =	
  owner	
  
	
  	
  	
  	
  }	
  
!
	
  	
  	
  	
  public	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  "Hello	
  "	
  +	
  name	
  +	
  ",	
  I	
  am	
  "	
  +	
  owner	
  
	
  	
  	
  	
  }	
  
}	
  
!
Greeter	
  greeter	
  =	
  new	
  Greeter()	
  
greeter.setOwner	
  "Guillaume"	
  
!
System.out.println	
  greeter.greet("Marion")
!23
Optional...
public	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  private	
  String	
  owner	
  
!
	
  	
  	
  	
  public	
  String	
  getOwner()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  owner	
  
	
  	
  	
  	
  }	
  
!
	
  	
  	
  	
  public	
  void	
  setOwner(String	
  owner)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  this.owner	
  =	
  owner	
  
	
  	
  	
  	
  }	
  
!
	
  	
  	
  	
  public	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  "Hello	
  "	
  +	
  name	
  +	
  ",	
  I	
  am	
  "	
  +	
  owner	
  
	
  	
  	
  	
  }	
  
}	
  
!
Greeter	
  greeter	
  =	
  new	
  Greeter()	
  
greeter.setOwner	
  "Guillaume"	
  
!
System.out.println	
  greeter.greet("Marion")

return keyword

!23
Optional...
public	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  private	
  String	
  owner	
  
!
	
  	
  	
  	
  public	
  String	
  getOwner()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  owner	
  
	
  	
  	
  	
  }	
  
!
	
  	
  	
  	
  public	
  void	
  setOwner(String	
  owner)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  this.owner	
  =	
  owner	
  
	
  	
  	
  	
  }	
  
!
	
  	
  	
  	
  public	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "Hello	
  "	
  +	
  name	
  +	
  ",	
  I	
  am	
  "	
  +	
  owner	
  
	
  	
  	
  	
  }	
  
}	
  
!
Greeter	
  greeter	
  =	
  new	
  Greeter()	
  
greeter.setOwner	
  "Guillaume"	
  
!
System.out.println	
  greeter.greet("Marion")
!24
Optional...
public	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  private	
  String	
  owner	
  
!
	
  	
  	
  	
  public	
  String	
  getOwner()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  owner	
  
	
  	
  	
  	
  }	
  
!
	
  	
  	
  	
  public	
  void	
  setOwner(String	
  owner)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  this.owner	
  =	
  owner	
  
	
  	
  	
  	
  }	
  
!
	
  	
  	
  	
  public	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "Hello	
  "	
  +	
  name	
  +	
  ",	
  I	
  am	
  "	
  +	
  owner	
  
	
  	
  	
  	
  }	
  
}	
  
!
Greeter	
  greeter	
  =	
  new	
  Greeter()	
  
greeter.setOwner	
  "Guillaume"	
  
!
System.out.println	
  greeter.greet("Marion")

public keyword

!24
Optional...
	
  	
  	
  	
  	
  	
  	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  private	
  String	
  owner	
  
!
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  getOwner()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  owner	
  
	
  	
  	
  	
  }	
  
!
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  void	
  setOwner(String	
  owner)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  this.owner	
  =	
  owner	
  
	
  	
  	
  	
  }	
  
!
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "Hello	
  "	
  +	
  name	
  +	
  ",	
  I	
  am	
  "	
  +	
  owner	
  
	
  	
  	
  	
  }	
  
}	
  
!
Greeter	
  greeter	
  =	
  new	
  Greeter()	
  
greeter.setOwner	
  "Guillaume"	
  
!
System.out.println	
  greeter.greet("Marion")
!25
Optional...
	
  	
  	
  	
  	
  	
  	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  private	
  String	
  owner	
  
!
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  getOwner()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  owner	
  
	
  	
  	
  	
  }	
  
!
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  void	
  setOwner(String	
  owner)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  this.owner	
  =	
  owner	
  
	
  	
  	
  	
  }	
  
!
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "Hello	
  "	
  +	
  name	
  +	
  ",	
  I	
  am	
  "	
  +	
  owner	
  
	
  	
  	
  	
  }	
  
}	
  
!
Greeter	
  greeter	
  =	
  new	
  Greeter()	
  
greeter.setOwner	
  "Guillaume"	
  
!
System.out.println	
  greeter.greet("Marion")

optional typing

!25
Optional...
	
  	
  	
  	
  	
  	
  	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  private	
  String	
  owner	
  
!
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  getOwner()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  owner	
  
	
  	
  	
  	
  }	
  
!
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  void	
  setOwner(String	
  owner)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  this.owner	
  =	
  owner	
  
	
  	
  	
  	
  }	
  
!
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "Hello	
  "	
  +	
  name	
  +	
  ",	
  I	
  am	
  "	
  +	
  owner	
  
	
  	
  	
  	
  }	
  
}	
  
!
def	
  	
  	
  	
  	
  greeter	
  =	
  new	
  Greeter()	
  
greeter.setOwner	
  "Guillaume"	
  
!
System.out.println	
  greeter.greet("Marion")
!26
Optional...
	
  	
  	
  	
  	
  	
  	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  private	
  String	
  owner	
  
!
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  getOwner()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  owner	
  
	
  	
  	
  	
  }	
  
!
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  void	
  setOwner(String	
  owner)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  this.owner	
  =	
  owner	
  
	
  	
  	
  	
  }	
  
!
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "Hello	
  "	
  +	
  name	
  +	
  ",	
  I	
  am	
  "	
  +	
  owner	
  
	
  	
  	
  	
  }	
  
}	
  
!
def	
  	
  	
  	
  	
  greeter	
  =	
  new	
  Greeter()	
  
greeter.setOwner	
  "Guillaume"	
  
!
System.out.println	
  greeter.greet("Marion")

handy println shortcut

!26
Optional...
	
  	
  	
  	
  	
  	
  	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  private	
  String	
  owner	
  
!
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  getOwner()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  owner	
  
	
  	
  	
  	
  }	
  
!
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  void	
  setOwner(String	
  owner)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  this.owner	
  =	
  owner	
  
	
  	
  	
  	
  }	
  
!
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "Hello	
  "	
  +	
  name	
  +	
  ",	
  I	
  am	
  "	
  +	
  owner	
  
	
  	
  	
  	
  }	
  
}	
  
!
def	
  	
  	
  	
  	
  greeter	
  =	
  new	
  Greeter()	
  
greeter.setOwner	
  "Guillaume"	
  
!
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  println	
  greeter.greet("Marion")
!27
Optional...

verbose Java properties!

	
  	
  	
  	
  	
  	
  	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  private	
  String	
  owner	
  
!
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  getOwner()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  owner	
  
	
  	
  	
  	
  }	
  
!
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  void	
  setOwner(String	
  owner)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  this.owner	
  =	
  owner	
  
	
  	
  	
  	
  }	
  
!
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "Hello	
  "	
  +	
  name	
  +	
  ",	
  I	
  am	
  "	
  +	
  owner	
  
	
  	
  	
  	
  }	
  
}	
  
!
def	
  	
  	
  	
  	
  greeter	
  =	
  new	
  Greeter()	
  
greeter.setOwner	
  "Guillaume"	
  
!
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  println	
  greeter.greet("Marion")
!27
Optional...
	
  	
  	
  	
  	
  	
  	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  owner	
  
!
!
!
!
!
!
!
!
!
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "Hello	
  "	
  +	
  name	
  +	
  ",	
  I	
  am	
  "	
  +	
  owner	
  
	
  	
  	
  	
  }	
  
}	
  
!
def	
  	
  	
  	
  	
  greeter	
  =	
  new	
  Greeter()	
  
greeter.setOwner	
  "Guillaume"	
  
!
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  println	
  greeter.greet("Marion")
!28
Optional...
	
  	
  	
  	
  	
  	
  	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  owner	
  
!
!
!
!
!
!
!
!
!
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "Hello	
  "	
  +	
  name	
  +	
  ",	
  I	
  am	
  "	
  +	
  owner	
  
	
  	
  	
  	
  }	
  
}	
  
!
def	
  	
  	
  	
  	
  greeter	
  =	
  new	
  Greeter()	
  
greeter.setOwner	
  "Guillaume"	
  
!
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  println	
  greeter.greet("Marion")

Property notation

!28
Optional...
	
  	
  	
  	
  	
  	
  	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  owner	
  
!
!
!
!
!
!
!
!
!
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "Hello	
  "	
  +	
  name	
  +	
  ",	
  I	
  am	
  "	
  +	
  owner	
  
	
  	
  	
  	
  }	
  
}	
  
!
def	
  	
  	
  	
  	
  greeter	
  =	
  new	
  Greeter()	
  
greeter.owner	
  	
  	
  	
  "Guillaume"	
  
!
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  println	
  greeter.greet("Marion")
!29
Optional...
	
  	
  	
  	
  	
  	
  	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  owner	
  
!
!
!
!
!
!
!
!
!
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "Hello	
  "	
  +	
  name	
  +	
  ",	
  I	
  am	
  "	
  +	
  owner	
  
	
  	
  	
  	
  }	
  
}	
  
!
def	
  	
  	
  	
  	
  greeter	
  =	
  new	
  Greeter()	
  
greeter.owner	
  	
  	
  	
  "Guillaume"	
  
!
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  println	
  greeter.greet("Marion")

Named argument
constructor

!29
Optional...
	
  	
  	
  	
  	
  	
  	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  owner	
  
!
!
!
!
!
!
!
!
!
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "Hello	
  "	
  +	
  name	
  +	
  ",	
  I	
  am	
  "	
  +	
  owner	
  
	
  	
  	
  	
  }	
  
}	
  
!
def	
  	
  	
  	
  	
  greeter	
  =	
  new	
  Greeter(owner:	
  "Guillaume")	
  
!
!
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  println	
  greeter.greet("Marion")
!30
Optional...
	
  	
  	
  	
  	
  	
  	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  owner	
  
!
!
!
!
!
!
!
!
!
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "Hello	
  "	
  +	
  name	
  +	
  ",	
  I	
  am	
  "	
  +	
  owner	
  
	
  	
  	
  	
  }	
  
}	
  
!
def	
  	
  	
  	
  	
  greeter	
  =	
  new	
  Greeter(owner:	
  "Guillaume")	
  
!
!
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  println	
  greeter.greet("Marion")

Interpolated strings!
(aka GStrings)

!30
Optional...
	
  	
  	
  	
  	
  	
  	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  owner	
  
!
!
!
!
!
!
!
!
!
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "Hello	
  ${name},	
  I	
  am	
  ${owner}"	
  
	
  	
  	
  	
  }	
  
}	
  
!
def	
  	
  	
  	
  	
  greeter	
  =	
  new	
  Greeter(owner:	
  "Guillaume")	
  
!
!
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  println	
  greeter.greet("Marion")
!31
Optional...
	
  	
  	
  	
  	
  	
  	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  owner	
  
!
!
!
!
!
!
!
!
!
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "Hello	
  ${name},	
  I	
  am	
  ${owner}"	
  
	
  	
  	
  	
  }	
  
}	
  
!
def	
  	
  	
  	
  	
  greeter	
  =	
  new	
  Greeter(owner:	
  "Guillaume")	
  
!
!
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  println	
  greeter.greet("Marion")

Let’s reformat that
mess of whitespace!

!31
Optional...
class	
  Greeter	
  {	
  
	
  	
  	
  	
  String	
  owner	
  
!
	
  	
  	
  	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  "Hello	
  ${name},	
  I	
  am	
  ${owner}"	
  
	
  	
  	
  	
  }	
  
}	
  
!
def	
  greeter	
  =	
  new	
  Greeter(owner:	
  "Guillaume")	
  
!
println	
  greeter.greet("Marion")

!32
Optional...
public	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  private	
  String	
  owner;	
  
!
	
  	
  	
  	
  public	
  String	
  getOwner()	
  {	
  
class	
  Greeter	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  owner;	
  
	
  	
  	
  	
  String	
  owner	
  
	
  	
  	
  	
  }	
  
!
!
	
  	
  	
  	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  public	
  void	
  setOwner(String	
  owner)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  "Hello	
  ${name},	
  I	
  am	
  ${owner}"	
  
	
  	
  	
  	
  	
  	
  	
  	
  this.owner	
  =	
  owner;	
  
	
  	
  	
  	
  }	
  
	
  	
  	
  	
  }	
  
}	
  
!
!
	
  	
  	
  	
  public	
  String	
  greet(String	
  name)	
  {	
  
def	
  greeter	
  =	
  new	
  Greeter(owner:	
  "Guillaume")	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  "Hello	
  "	
  +	
  name	
  +	
  ",	
  I	
  am	
  "	
  +	
  owner;	
  
!
	
  	
  	
  	
  }	
  
println	
  greeter.greet("Marion")
}	
  
!
Greeter	
  greeter	
  =	
  new	
  Greeter();	
  
greeter.setOwner("Guillaume");	
  
!
System.out.println(greeter.greet("Marion"));
!32
Optional...
class	
  Greeter	
  {	
  
	
  	
  	
  	
  String	
  owner	
  
!
	
  	
  	
  	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  "Hello	
  ${name},	
  I	
  am	
  ${owner}"	
  
	
  	
  	
  	
  }	
  
}	
  
!
def	
  greeter	
  =	
  new	
  Greeter(owner:	
  "Guillaume")	
  
!
println	
  greeter.greet("Marion")

!32
Native syntax constructs
//	
  closures	
  
def	
  adder	
  =	
  {	
  a,	
  b	
  -­‐>	
  a	
  +	
  b	
  }	
  
!

//	
  lists	
  
def	
  list	
  =	
  [1,	
  2,	
  3,	
  4,	
  5]	
  
!

//	
  maps	
  
def	
  map	
  =	
  [a:	
  1,	
  b:	
  2,	
  c:	
  3]	
  
!

//	
  regular	
  expressions	
  
def	
  regex	
  =	
  ~/.*foo.*/	
  
!

//	
  ranges	
  
def	
  range	
  128..255
!33
Closures — the basics

def	
  adder	
  =	
  {	
  a,	
  b	
  -­‐>	
  a	
  +	
  b	
  }	
  
!

assert	
  adder(1,	
  2)	
  ==	
  3	
  
assert	
  adder('a',	
  'b')	
  ==	
  'ab'

!34
Closures — the basics
Closure
parameters

def	
  adder	
  =	
  {	
  a,	
  b	
  -­‐>	
  a	
  +	
  b	
  }	
  
!

assert	
  adder(1,	
  2)	
  ==	
  3	
  
assert	
  adder('a',	
  'b')	
  ==	
  'ab'

!34
Closures — the basics
Assign a function
into a variable

Closure
parameters

def	
  adder	
  =	
  {	
  a,	
  b	
  -­‐>	
  a	
  +	
  b	
  }	
  
!

assert	
  adder(1,	
  2)	
  ==	
  3	
  
assert	
  adder('a',	
  'b')	
  ==	
  'ab'

!34
Closures — the basics
Assign a function
into a variable

Closure
parameters

def	
  adder	
  =	
  {	
  a,	
  b	
  -­‐>	
  a	
  +	
  b	
  }	
  
!

assert	
  adder(1,	
  2)	
  ==	
  3	
  
assert	
  adder('a',	
  'b')	
  ==	
  'ab'
Short form of:
adder.call(‘a’, ‘b’)
!34
Closures — the basics
Assign a function
into a variable

Closure
parameters

def	
  adder	
  =	
  {	
  a,	
  b	
  -­‐>	
  a	
  +	
  b	
  }	
  
!

assert	
  adder(1,	
  2)	
  ==	
  3	
  
assert	
  adder('a',	
  'b')	
  ==	
  'ab'
Short form of:
adder.call(‘a’, ‘b’)
!34

Genericity with
duck typing &
operator overloading
Closures — explicit type

!

def	
  intAdder	
  =	
  {	
  int	
  a,	
  int	
  b	
  -­‐>	
  a	
  +	
  b	
  }	
  

!35
Closures — explicit type
Be explicit about
the types
!

def	
  intAdder	
  =	
  {	
  int	
  a,	
  int	
  b	
  -­‐>	
  a	
  +	
  b	
  }	
  

!35
Closures — implicit parameter

def	
  doubler	
  =	
  {	
  it	
  *	
  2	
  }	
  
!

assert	
  doubler(3)	
  ==	
  6	
  
assert	
  doubler('a')	
  ==	
  'aa'

!36
Closures — implicit parameter
Implicit
parameter

def	
  doubler	
  =	
  {	
  it	
  *	
  2	
  }	
  
!

assert	
  doubler(3)	
  ==	
  6	
  
assert	
  doubler('a')	
  ==	
  'aa'

!36
Closures — implicit parameter
Implicit
parameter

def	
  doubler	
  =	
  {	
  it	
  *	
  2	
  }	
  
!

assert	
  doubler(3)	
  ==	
  6	
  
assert	
  doubler('a')	
  ==	
  'aa'
Multiply also
defined on strings
!36
Closures — variable arguments

def	
  sum	
  =	
  {	
  ...	
  elements	
  -­‐>	
  

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  elements.sum()	
  }	
  
!

assert	
  sum(1,	
  2)	
  ==	
  3	
  
assert	
  sum('a',	
  'b',	
  'c')	
  ==	
  'abc'

!37
Closures — variable arguments
Variable number
of arguments

def	
  sum	
  =	
  {	
  ...	
  elements	
  -­‐>	
  

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  elements.sum()	
  }	
  
!

assert	
  sum(1,	
  2)	
  ==	
  3	
  
assert	
  sum('a',	
  'b',	
  'c')	
  ==	
  'abc'

!37
Closures — variable arguments
You can specify
the type: int...

Variable number
of arguments

def	
  sum	
  =	
  {	
  ...	
  elements	
  -­‐>	
  

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  elements.sum()	
  }	
  
!

assert	
  sum(1,	
  2)	
  ==	
  3	
  
assert	
  sum('a',	
  'b',	
  'c')	
  ==	
  'abc'

!37
Closures — default values

def	
  mult	
  =	
  {	
  int	
  a,	
  int	
  b	
  =	
  10	
  -­‐>	
  a	
  *	
  b	
  }	
  
!

assert	
  mult(2,	
  3)	
  ==	
  6	
  
assert	
  mult(5)	
  ==	
  50

!38
Closures — default values
Default value
def	
  mult	
  =	
  {	
  int	
  a,	
  int	
  b	
  =	
  10	
  -­‐>	
  a	
  *	
  b	
  }	
  
!

assert	
  mult(2,	
  3)	
  ==	
  6	
  
assert	
  mult(5)	
  ==	
  50

!38
Closures — default values
Default value
def	
  mult	
  =	
  {	
  int	
  a,	
  int	
  b	
  =	
  10	
  -­‐>	
  a	
  *	
  b	
  }	
  
!

assert	
  mult(2,	
  3)	
  ==	
  6	
  
assert	
  mult(5)	
  ==	
  50

!38

Provided value
for b
Closures — default values
Default value
def	
  mult	
  =	
  {	
  int	
  a,	
  int	
  b	
  =	
  10	
  -­‐>	
  a	
  *	
  b	
  }	
  
!

assert	
  mult(2,	
  3)	
  ==	
  6	
  
assert	
  mult(5)	
  ==	
  50

Default value
used for b
!38

Provided value
for b
Closures — methods as functions

def	
  logBase10	
  =	
  Math.&log10	
  
def	
  printer	
  =	
  System.out.&println	
  
!

assert	
  logBase10(10)	
  ==	
  1	
  
printer	
  'abc'

!39
Closures — methods as functions
Turn a method into a closure function

def	
  logBase10	
  =	
  Math.&log10	
  
def	
  printer	
  =	
  System.out.&println	
  
!

assert	
  logBase10(10)	
  ==	
  1	
  
printer	
  'abc'

!39
Closures — map / filter / reduce

!40
Closures — map / filter / reduce
@groovy.transform.Immutable

class	
  Person	
  {

	
  	
  	
  	
  String	
  name

	
  	
  	
  	
  int	
  age

}

!40
Closures — map / filter / reduce
@groovy.transform.Immutable

class	
  Person	
  {

	
  	
  	
  	
  String	
  name

	
  	
  	
  	
  int	
  age

}

!40
Closures — map / filter / reduce
@groovy.transform.Immutable

class	
  Person	
  {

	
  	
  	
  	
  String	
  name

	
  	
  	
  	
  int	
  age

}
def	
  persons	
  =	
  [

	
  	
  	
  	
  new	
  Person('Guillaume',	
  36),

	
  	
  	
  	
  new	
  Person('Marion',	
  5),

	
  	
  	
  	
  new	
  Person('Erine',	
  1)

]

!40
Closures — map / filter / reduce
@groovy.transform.Immutable

class	
  Person	
  {

	
  	
  	
  	
  String	
  name

	
  	
  	
  	
  int	
  age

}
def	
  persons	
  =	
  [

	
  	
  	
  	
  new	
  Person('Guillaume',	
  36),

	
  	
  	
  	
  new	
  Person('Marion',	
  5),

	
  	
  	
  	
  new	
  Person('Erine',	
  1)

]

!40
Closures — map / filter / reduce
@groovy.transform.Immutable

class	
  Person	
  {

	
  	
  	
  	
  String	
  name

	
  	
  	
  	
  int	
  age

}
def	
  persons	
  =	
  [

	
  	
  	
  	
  new	
  Person('Guillaume',	
  36),

	
  	
  	
  	
  new	
  Person('Marion',	
  5),

	
  	
  	
  	
  new	
  Person('Erine',	
  1)

]
def	
  names	
  =

	
  	
  	
  	
  persons.findAll	
  {	
  it.age	
  <	
  18	
  }

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  .collect	
  {	
  it.name.toUpperCase()	
  }

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  .sort()

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  .join(',	
  ')
!40
Closures — map / filter / reduce
@groovy.transform.Immutable

class	
  Person	
  {

	
  	
  	
  	
  String	
  name

	
  	
  	
  	
  int	
  age

}
def	
  persons	
  =	
  [

	
  	
  	
  	
  new	
  Person('Guillaume',	
  36),

	
  	
  	
  	
  new	
  Person('Marion',	
  5),

	
  	
  	
  	
  new	
  Person('Erine',	
  1)

]
def	
  names	
  =

	
  	
  	
  	
  persons.findAll	
  {	
  it.age	
  <	
  18	
  }

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  .collect	
  {	
  it.name.toUpperCase()	
  }

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  .sort()

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  .join(',	
  ')
!40
Closures — map / filter / reduce
@groovy.transform.Immutable

class	
  Person	
  {

	
  	
  	
  	
  String	
  name

	
  	
  	
  	
  int	
  age

}
def	
  persons	
  =	
  [

	
  	
  	
  	
  new	
  Person('Guillaume',	
  36),

	
  	
  	
  	
  new	
  Person('Marion',	
  5),

	
  	
  	
  	
  new	
  Person('Erine',	
  1)

]
def	
  names	
  =

	
  	
  	
  	
  persons.findAll	
  {	
  it.age	
  <	
  18	
  }

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  .collect	
  {	
  it.name.toUpperCase()	
  }

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  .sort()

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  .join(',	
  ')
assert	
  names	
  ==	
  "ERINE,	
  MARION"
!40
Closures — map / filter / reduce
@groovy.transform.Immutable

class	
  Person	
  {

	
  	
  	
  	
  String	
  name

	
  	
  	
  	
  int	
  age

}
def	
  persons	
  =	
  [

	
  	
  	
  	
  new	
  Person('Guillaume',	
  36),

	
  	
  	
  	
  new	
  Person('Marion',	
  5),

	
  	
  	
  	
  new	
  Person('Erine',	
  1)

]

find/findAll, inject, collect,
flatten, min/max, unique,
reverse, collate, groupBy, any/
every, head/tail/last, count/
countBy, combinations/
permutations/subsequences/
transpose, withDefault/
withLazyDefault

def	
  names	
  =

	
  	
  	
  	
  persons.findAll	
  {	
  it.age	
  <	
  18	
  }

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  .collect	
  {	
  it.name.toUpperCase()	
  }

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  .sort()

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  .join(',	
  ')
assert	
  names	
  ==	
  "ERINE,	
  MARION"
!40
Closures — resource handling

new	
  File('bible.txt').withReader	
  {	
  r	
  -­‐>	
  
	
  	
  	
  	
  new	
  File('out.txt').withWriter	
  {	
  w	
  -­‐>	
  
	
  	
  	
  	
  	
  	
  	
  	
  r.eachLine	
  {	
  line	
  -­‐>	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  (line.contains('Groovy'))	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  w	
  <<	
  line.toUpperCase()	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  }	
  
}

!41
Closures — resource handling
Take care of properly
opening / closing resources
new	
  File('bible.txt').withReader	
  {	
  r	
  -­‐>	
  
	
  	
  	
  	
  new	
  File('out.txt').withWriter	
  {	
  w	
  -­‐>	
  
	
  	
  	
  	
  	
  	
  	
  	
  r.eachLine	
  {	
  line	
  -­‐>	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  (line.contains('Groovy'))	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  w	
  <<	
  line.toUpperCase()	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  }	
  
}

!41
Closures — custom control structures

void	
  unless(boolean	
  cond,	
  Closure	
  c)	
  {	
  
	
  	
  	
  	
  if	
  (!cond)	
  c()	
  
}	
  
!

unless	
  (10	
  <	
  9)	
  {	
  
	
  	
  	
  	
  println	
  "less"	
  
}

!42
Closures — custom control structures
Closure as last argument
void	
  unless(boolean	
  cond,	
  Closure	
  c)	
  {	
  
	
  	
  	
  	
  if	
  (!cond)	
  c()	
  
}	
  
!

unless	
  (10	
  <	
  9)	
  {	
  
	
  	
  	
  	
  println	
  "less"	
  
}

!42
Closures — custom control structures
Closure as last argument
void	
  unless(boolean	
  cond,	
  Closure	
  c)	
  {	
  
	
  	
  	
  	
  if	
  (!cond)	
  c()	
  
}	
  
!

unless	
  (10	
  <	
  9)	
  {	
  
	
  	
  	
  	
  println	
  "less"	
  
}

!42

Equivalent to:
unless(10<9, {...})
Lists
def	
  list	
  =	
  ['a',	
  'b',	
  'c']	
  
!

list	
  <<	
  'd'	
  
assert	
  list.contains('d')	
  
!

assert	
  list.findAll	
  {	
  it.startsWith	
  'a'	
  }.size()	
  ==	
  1	
  
assert	
  list.collect	
  {	
  it.toUpperCase()	
  }	
  

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ==	
  ['A',	
  'B',	
  'C',	
  'D']	
  
assert	
  list.inject('')	
  {	
  a,	
  b	
  -­‐>	
  a	
  +	
  b	
  }	
  ==	
  'abcd'

!43
Lists
List definition
def	
  list	
  =	
  ['a',	
  'b',	
  'c']	
  
!

list	
  <<	
  'd'	
  
assert	
  list.contains('d')	
  
!

assert	
  list.findAll	
  {	
  it.startsWith	
  'a'	
  }.size()	
  ==	
  1	
  
assert	
  list.collect	
  {	
  it.toUpperCase()	
  }	
  

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ==	
  ['A',	
  'B',	
  'C',	
  'D']	
  
assert	
  list.inject('')	
  {	
  a,	
  b	
  -­‐>	
  a	
  +	
  b	
  }	
  ==	
  'abcd'

!43
Lists
List definition
def	
  list	
  =	
  ['a',	
  'b',	
  'c']	
  
!

Append an element
(operator overloading)

list	
  <<	
  'd'	
  
assert	
  list.contains('d')	
  
!

assert	
  list.findAll	
  {	
  it.startsWith	
  'a'	
  }.size()	
  ==	
  1	
  
assert	
  list.collect	
  {	
  it.toUpperCase()	
  }	
  

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ==	
  ['A',	
  'B',	
  'C',	
  'D']	
  
assert	
  list.inject('')	
  {	
  a,	
  b	
  -­‐>	
  a	
  +	
  b	
  }	
  ==	
  'abcd'

!43
Lists
List definition
def	
  list	
  =	
  ['a',	
  'b',	
  'c']	
  
!

Append an element
(operator overloading)

list	
  <<	
  'd'	
  
assert	
  list.contains('d')	
  
!

assert	
  list.findAll	
  {	
  it.startsWith	
  'a'	
  }.size()	
  ==	
  1	
  
assert	
  list.collect	
  {	
  it.toUpperCase()	
  }	
  

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ==	
  ['A',	
  'B',	
  'C',	
  'D']	
  
assert	
  list.inject('')	
  {	
  a,	
  b	
  -­‐>	
  a	
  +	
  b	
  }	
  ==	
  'abcd'

Functional-style
map / filter / reduce
with closures
!43
Maps

def	
  map	
  =	
  [name:	
  'Guillaume',	
  age:	
  36]	
  
!

map.daughters	
  =	
  ['Marion',	
  'Erine']	
  
!

assert	
  map['daughters'].contains('Marion')

!44
Maps
Map definition
def	
  map	
  =	
  [name:	
  'Guillaume',	
  age:	
  36]	
  
!

map.daughters	
  =	
  ['Marion',	
  'Erine']	
  
!

assert	
  map['daughters'].contains('Marion')

!44
Maps
Map definition
def	
  map	
  =	
  [name:	
  'Guillaume',	
  age:	
  36]	
  
!

map.daughters	
  =	
  ['Marion',	
  'Erine']	
  
!

assert	
  map['daughters'].contains('Marion')

Indexed access

!44
Maps
Map definition
def	
  map	
  =	
  [name:	
  'Guillaume',	
  age:	
  36]	
  
!

map.daughters	
  =	
  ['Marion',	
  'Erine']	
  
!

assert	
  map['daughters'].contains('Marion')

Property
notation access
!44

Indexed access
Regular expressions
def	
  pattern	
  =	
  ~/.*foo.*/	
  
!

assert	
  "Alibaba"	
  ==~	
  /.*(ba){2}/	
  
!

def	
  matcher	
  =	
  "Superman"	
  =~	
  /([A-­‐Z][a-­‐z]+)man/	
  
assert	
  matcher[0][0]	
  ==	
  'Superman'	
  
assert	
  matcher[0][1]	
  ==	
  'Super'	
  
!

'75001	
  Paris'.find(/(d{5})s(w)+/)	
  {	
  match,	
  zip,	
  town	
  -­‐>	
  
	
  	
  	
  	
  println	
  "The	
  Zip	
  code	
  of	
  ${town}	
  is	
  ${zip}"	
  
}

!45
Regular expressions
Pattern
def	
  pattern	
  =	
  ~/.*foo.*/	
  
!

assert	
  "Alibaba"	
  ==~	
  /.*(ba){2}/	
  
!

def	
  matcher	
  =	
  "Superman"	
  =~	
  /([A-­‐Z][a-­‐z]+)man/	
  
assert	
  matcher[0][0]	
  ==	
  'Superman'	
  
assert	
  matcher[0][1]	
  ==	
  'Super'	
  
!

'75001	
  Paris'.find(/(d{5})s(w)+/)	
  {	
  match,	
  zip,	
  town	
  -­‐>	
  
	
  	
  	
  	
  println	
  "The	
  Zip	
  code	
  of	
  ${town}	
  is	
  ${zip}"	
  
}

!45
Regular expressions
Pattern

Match

def	
  pattern	
  =	
  ~/.*foo.*/	
  
!

assert	
  "Alibaba"	
  ==~	
  /.*(ba){2}/	
  
!

def	
  matcher	
  =	
  "Superman"	
  =~	
  /([A-­‐Z][a-­‐z]+)man/	
  
assert	
  matcher[0][0]	
  ==	
  'Superman'	
  
assert	
  matcher[0][1]	
  ==	
  'Super'	
  
!

'75001	
  Paris'.find(/(d{5})s(w)+/)	
  {	
  match,	
  zip,	
  town	
  -­‐>	
  
	
  	
  	
  	
  println	
  "The	
  Zip	
  code	
  of	
  ${town}	
  is	
  ${zip}"	
  
}

!45
Regular expressions
Pattern

Match

def	
  pattern	
  =	
  ~/.*foo.*/	
  
!

assert	
  "Alibaba"	
  ==~	
  /.*(ba){2}/	
  

Find

!

def	
  matcher	
  =	
  "Superman"	
  =~	
  /([A-­‐Z][a-­‐z]+)man/	
  
assert	
  matcher[0][0]	
  ==	
  'Superman'	
  
assert	
  matcher[0][1]	
  ==	
  'Super'	
  
!

'75001	
  Paris'.find(/(d{5})s(w)+/)	
  {	
  match,	
  zip,	
  town	
  -­‐>	
  
	
  	
  	
  	
  println	
  "The	
  Zip	
  code	
  of	
  ${town}	
  is	
  ${zip}"	
  
}

!45
Regular expressions
Pattern

Match

def	
  pattern	
  =	
  ~/.*foo.*/	
  
!

assert	
  "Alibaba"	
  ==~	
  /.*(ba){2}/	
  

Find

!

def	
  matcher	
  =	
  "Superman"	
  =~	
  /([A-­‐Z][a-­‐z]+)man/	
  
assert	
  matcher[0][0]	
  ==	
  'Superman'	
  
assert	
  matcher[0][1]	
  ==	
  'Super'	
  
!

'75001	
  Paris'.find(/(d{5})s(w)+/)	
  {	
  match,	
  zip,	
  town	
  -­‐>	
  
	
  	
  	
  	
  println	
  "The	
  Zip	
  code	
  of	
  ${town}	
  is	
  ${zip}"	
  
}

Nice way to decompose the matched regions
!45
Ranges
def	
  range	
  =	
  'a'..'z'	
  
!

assert	
  range.contains('m')	
  
assert	
  range.contains('z')	
  
!

def	
  exclusive	
  =	
  1..<10	
  
!

assert	
  !exclusive.contains(10)	
  
!

def	
  reverse	
  =	
  10..0	
  
!

assert	
  reverse[0]	
  ==	
  10	
  
assert	
  reverse[-­‐1]	
  ==	
  0
!46
Ranges

Range

def	
  range	
  =	
  'a'..'z'	
  
!

assert	
  range.contains('m')	
  
assert	
  range.contains('z')	
  
!

def	
  exclusive	
  =	
  1..<10	
  
!

assert	
  !exclusive.contains(10)	
  
!

def	
  reverse	
  =	
  10..0	
  
!

assert	
  reverse[0]	
  ==	
  10	
  
assert	
  reverse[-­‐1]	
  ==	
  0
!46
Ranges

Range

def	
  range	
  =	
  'a'..'z'	
  
!

assert	
  range.contains('m')	
  
assert	
  range.contains('z')	
  
!

def	
  exclusive	
  =	
  1..<10	
  

Excluded upper bound

!

assert	
  !exclusive.contains(10)	
  
!

def	
  reverse	
  =	
  10..0	
  
!

assert	
  reverse[0]	
  ==	
  10	
  
assert	
  reverse[-­‐1]	
  ==	
  0
!46
Ranges

Range

def	
  range	
  =	
  'a'..'z'	
  
!

assert	
  range.contains('m')	
  
assert	
  range.contains('z')	
  
!

def	
  exclusive	
  =	
  1..<10	
  

Excluded upper bound

!

assert	
  !exclusive.contains(10)	
  
!

def	
  reverse	
  =	
  10..0	
  
!

assert	
  reverse[0]	
  ==	
  10	
  
assert	
  reverse[-­‐1]	
  ==	
  0
!46

Reverse range
Ranges

Range

def	
  range	
  =	
  'a'..'z'	
  
!

assert	
  range.contains('m')	
  
assert	
  range.contains('z')	
  
!

def	
  exclusive	
  =	
  1..<10	
  

Excluded upper bound

!

assert	
  !exclusive.contains(10)	
  
!

def	
  reverse	
  =	
  10..0	
  

Reverse range

!

assert	
  reverse[0]	
  ==	
  10	
  
assert	
  reverse[-­‐1]	
  ==	
  0
!46

Negative index count
from the end
Strings, GStrings, multiline strings

def	
  name	
  =	
  'Groovy'	
  
def	
  tmpl	
  =	
  """	
  
	
  	
  	
  	
  Dear	
  Mr	
  ${name},	
  
	
  	
  	
  	
  You're	
  the	
  winner	
  of	
  the	
  lottery!	
  
	
  	
  	
  	
  Yours	
  sincerly,	
  
	
  	
  	
  	
  Dave	
  
"""	
  
!

assert	
  tmpl.toString().contains('Groovy')

!47
Strings, GStrings, multiline strings
Plain java.lang.String
def	
  name	
  =	
  'Groovy'	
  
def	
  tmpl	
  =	
  """	
  
	
  	
  	
  	
  Dear	
  Mr	
  ${name},	
  
	
  	
  	
  	
  You're	
  the	
  winner	
  of	
  the	
  lottery!	
  
	
  	
  	
  	
  Yours	
  sincerly,	
  
	
  	
  	
  	
  Dave	
  
"""	
  
!

assert	
  tmpl.toString().contains('Groovy')

!47
Strings, GStrings, multiline strings
Plain java.lang.String
def	
  name	
  =	
  'Groovy'	
  
Multiline string with
def	
  tmpl	
  =	
  """	
  
expression interpolation
	
  	
  	
  	
  Dear	
  Mr	
  ${name},	
  
	
  	
  	
  	
  You're	
  the	
  winner	
  of	
  the	
  lottery!	
  
	
  	
  	
  	
  Yours	
  sincerly,	
  
	
  	
  	
  	
  Dave	
  
"""	
  
!

assert	
  tmpl.toString().contains('Groovy')

!47
Surprising numbers...

System.out.println(	
  2.0	
  -­‐	
  1.1	
  );

!48
Surprising numbers...

System.out.println(	
  2.0	
  -­‐	
  1.1	
  );
0.8999999999999999

!48
Surprising numbers...

System.out.println(	
  2.0	
  -­‐	
  1.1	
  );
0.8999999999999999

!48
Surprising numbers...

System.out.println(	
  3	
  /	
  2	
  );

!49
Surprising numbers...

System.out.println(	
  3	
  /	
  2	
  );
1

!49
Surprising numbers...

System.out.println(	
  3	
  /	
  2	
  );
1

!49
BigDecimal by default!

assert	
  2.0	
  -­‐	
  1.1	
  ==	
  0.9
assert	
  3	
  /	
  2	
  ==	
  1.5

!50
BigDecimal by default!

assert	
  2.0	
  -­‐	
  1.1	
  ==	
  0.9
assert	
  3	
  /	
  2	
  ==	
  1.5
One of the reasons why microbenchmarks sometimes showed
Groovy to be slow...
!50
BigDecimal by default!

assert	
  2.0	
  -­‐	
  1.1	
  ==	
  0.9
assert	
  3	
  /	
  2	
  ==	
  1.5
One of the reasons why microbenchmarks sometimes showed
Groovy to be slow...
!50

But you can use doubles & floats
for performance, with ‘d’ or ‘f ’
suffixes or with explicit type
What makes Groovy Groovy  - Guillaume Laforge (Pivotal)
Powerful
switch / case
on steroids
Powerful
switch / case
on steroids
switch(obj)	
  {	
  
	
  	
  	
  	
  case	
  123:	
  	
  	
  	
  	
  	
  	
  	
  	
  "number	
  123";	
  	
  	
  	
  	
  	
  	
  break	
  
	
  	
  	
  	
  case	
  "abc":	
  	
  	
  	
  	
  	
  	
  "string	
  abc";	
  	
  	
  	
  	
  	
  	
  break	
  
	
  	
  	
  	
  case	
  String:	
  	
  	
  	
  	
  	
  "is	
  a	
  string";	
  	
  	
  	
  	
  	
  break	
  
	
  	
  	
  	
  case	
  [1,	
  2,	
  3]:	
  	
  	
  "in	
  list";	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  break	
  
	
  	
  	
  	
  case	
  ~/.*o+.*/:	
  	
  	
  "regex	
  match";	
  	
  	
  	
  	
  	
  break	
  
	
  	
  	
  	
  case	
  {	
  it	
  <	
  3	
  }:	
  	
  "closure	
  criteria";	
  break	
  
	
  	
  	
  	
  default:	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "unknown"	
  
}
Named arguments

move	
  obj,	
  x:	
  3,	
  y:	
  4

!52
Named arguments

move	
  obj,	
  x:	
  3,	
  y:	
  4
Normal argument

!52
Named arguments

move	
  obj,	
  x:	
  3,	
  y:	
  4
Normal argument

!52

Named argument
Named arguments

move	
  obj,	
  x:	
  3,	
  y:	
  4
Normal argument
Calls:
move(Map m, Object)

!52

Named argument
Command chains
• Ability to chain method calls 

without parentheses and dots

move	
  forward	
  at	
  3.km/h

!53
Command chains
• Ability to chain method calls 

without parentheses and dots

move	
  forward	
  at	
  3.km/h
Actually equivalent to:
move(forward).at(3.getKm().div(h))

!53
Named arguments & command chains

check	
  that:	
  vodka	
  tastes	
  good

!54
Named arguments & command chains

check	
  that:	
  vodka	
  tastes	
  good
Will call:
check(that: vodka).tastes(good)

!54
Multiple assignment & destructuring
def	
  (a,	
  b)	
  =	
  ['A',	
  'B']	
  
!

(a,	
  b)	
  =	
  [b,	
  a]	
  
!

def	
  (int	
  i,	
  int	
  j)	
  =	
  [1,	
  2]	
  
!

def	
  geocode(String	
  place)	
  {	
  
	
  	
  	
  	
  return	
  [45.4,	
  2.3]	
  
}	
  
!

def	
  (la,	
  lo)	
  =	
  geocode("Paris")	
  
!

assert	
  la	
  ==	
  45.4	
  &&	
  lo	
  ==	
  2.3
!55
Multiple assignment & destructuring
def	
  (a,	
  b)	
  =	
  ['A',	
  'B']	
  
!

(a,	
  b)	
  =	
  [b,	
  a]	
  

Classic « swap »

!

def	
  (int	
  i,	
  int	
  j)	
  =	
  [1,	
  2]	
  
!

def	
  geocode(String	
  place)	
  {	
  
	
  	
  	
  	
  return	
  [45.4,	
  2.3]	
  
}	
  
!

def	
  (la,	
  lo)	
  =	
  geocode("Paris")	
  
!

assert	
  la	
  ==	
  45.4	
  &&	
  lo	
  ==	
  2.3
!55
Multiple assignment & destructuring
def	
  (a,	
  b)	
  =	
  ['A',	
  'B']	
  
!

With types

(a,	
  b)	
  =	
  [b,	
  a]	
  

Classic « swap »

!

def	
  (int	
  i,	
  int	
  j)	
  =	
  [1,	
  2]	
  
!

def	
  geocode(String	
  place)	
  {	
  
	
  	
  	
  	
  return	
  [45.4,	
  2.3]	
  
}	
  
!

def	
  (la,	
  lo)	
  =	
  geocode("Paris")	
  
!

assert	
  la	
  ==	
  45.4	
  &&	
  lo	
  ==	
  2.3
!55
Multiple assignment & destructuring
def	
  (a,	
  b)	
  =	
  ['A',	
  'B']	
  
!

With types

(a,	
  b)	
  =	
  [b,	
  a]	
  

Classic « swap »

!

def	
  (int	
  i,	
  int	
  j)	
  =	
  [1,	
  2]	
  

Method
returning a list

!

def	
  geocode(String	
  place)	
  {	
  
	
  	
  	
  	
  return	
  [45.4,	
  2.3]	
  
}	
  
!

def	
  (la,	
  lo)	
  =	
  geocode("Paris")	
  
!

assert	
  la	
  ==	
  45.4	
  &&	
  lo	
  ==	
  2.3
!55
Multiple assignment & destructuring
def	
  (a,	
  b)	
  =	
  ['A',	
  'B']	
  
!

With types

(a,	
  b)	
  =	
  [b,	
  a]	
  

Classic « swap »

!

def	
  (int	
  i,	
  int	
  j)	
  =	
  [1,	
  2]	
  

Method
returning a list

!

def	
  geocode(String	
  place)	
  {	
  
	
  	
  	
  	
  return	
  [45.4,	
  2.3]	
  
}	
  
Destructuring
!

def	
  (la,	
  lo)	
  =	
  geocode("Paris")	
  
!

assert	
  la	
  ==	
  45.4	
  &&	
  lo	
  ==	
  2.3
!55
Multiple assignment and destructuring
class	
  Point	
  {	
  
	
  	
  	
  	
  double	
  x,	
  y	
  
!

	
  	
  	
  	
  double	
  getAt(int	
  idx)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  if	
  (idx	
  ==	
  0)	
  x	
  
	
  	
  	
  	
  	
  	
  	
  	
  else	
  if	
  (idx	
  ==	
  1)	
  y	
  
	
  	
  	
  	
  	
  	
  	
  	
  else	
  throw	
  new	
  Exception("Wrong	
  index")	
  
	
  	
  	
  	
  }	
  
}	
  
!

def	
  (x,	
  y)	
  =	
  new	
  Point(x:	
  48.3,	
  y:	
  3.5)	
  
!

assert	
  x	
  ==	
  48.3	
  &&	
  y	
  ==	
  3.5
!56
Multiple assignment and destructuring
class	
  Point	
  {	
  
	
  	
  	
  	
  double	
  x,	
  y	
  

Method signature
convention: getAt(int)

!

	
  	
  	
  	
  double	
  getAt(int	
  idx)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  if	
  (idx	
  ==	
  0)	
  x	
  
	
  	
  	
  	
  	
  	
  	
  	
  else	
  if	
  (idx	
  ==	
  1)	
  y	
  
	
  	
  	
  	
  	
  	
  	
  	
  else	
  throw	
  new	
  Exception("Wrong	
  index")	
  
	
  	
  	
  	
  }	
  
}	
  
!

def	
  (x,	
  y)	
  =	
  new	
  Point(x:	
  48.3,	
  y:	
  3.5)	
  
!

assert	
  x	
  ==	
  48.3	
  &&	
  y	
  ==	
  3.5
!56
Multiple assignment and destructuring
class	
  Point	
  {	
  
	
  	
  	
  	
  double	
  x,	
  y	
  

Method signature
convention: getAt(int)

!

	
  	
  	
  	
  double	
  getAt(int	
  idx)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  if	
  (idx	
  ==	
  0)	
  x	
  
	
  	
  	
  	
  	
  	
  	
  	
  else	
  if	
  (idx	
  ==	
  1)	
  y	
  
	
  	
  	
  	
  	
  	
  	
  	
  else	
  throw	
  new	
  Exception("Wrong	
  index")	
  
	
  	
  	
  	
  }	
  
}	
  
Transparent destructuring
!

def	
  (x,	
  y)	
  =	
  new	
  Point(x:	
  48.3,	
  y:	
  3.5)	
  
!

assert	
  x	
  ==	
  48.3	
  &&	
  y	
  ==	
  3.5
!56
Builders — JSON builder
import	
  groovy.json.*	
  
!

def	
  json	
  =	
  new	
  JsonBuilder()	
  
json.person	
  {	
  
	
  	
  	
  	
  name	
  'Guillaume'	
  
	
  	
  	
  	
  age	
  36	
  
	
  	
  	
  	
  daughters	
  'Marion',	
  'Erine'	
  
	
  	
  	
  	
  address	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  street	
  '1	
  Main	
  Street'	
  
	
  	
  	
  	
  	
  	
  	
  	
  zip	
  75001	
  
	
  	
  	
  	
  	
  	
  	
  	
  city	
  'Paris'	
  
	
  	
  	
  	
  }	
  
}
!57
Builders — JSON builder
import	
  groovy.json.*	
  

Hierarchical data
def	
  json	
  =	
  new	
  JsonBuilder()	
   representation
!

json.person	
  {	
  
	
  	
  	
  	
  name	
  'Guillaume'	
  
	
  	
  	
  	
  age	
  36	
  
	
  	
  	
  	
  daughters	
  'Marion',	
  'Erine'	
  
	
  	
  	
  	
  address	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  street	
  '1	
  Main	
  Street'	
  
	
  	
  	
  	
  	
  	
  	
  	
  zip	
  75001	
  
	
  	
  	
  	
  	
  	
  	
  	
  city	
  'Paris'	
  
	
  	
  	
  	
  }	
  
}
!57
Builders — JSON builder
import	
  groovy.json.*	
  

Hierarchical data
def	
  json	
  =	
  new	
  JsonBuilder()	
   representation
!

json.person	
  {	
  
	
  	
  	
  	
  name	
  'Guillaume'	
  
Closure blocks
	
  	
  	
  	
  age	
  36	
  
delimiting
	
  	
  	
  	
  daughters	
  'Marion',	
  'Erine'	
  the
structure
	
  	
  	
  	
  address	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  street	
  '1	
  Main	
  Street'	
  
	
  	
  	
  	
  	
  	
  	
  	
  zip	
  75001	
  
	
  	
  	
  	
  	
  	
  	
  	
  city	
  'Paris'	
  
	
  	
  	
  	
  }	
  
}
!57
Builders — JSON builder
import	
  groovy.json.*	
  

Hierarchical data
{
"person": {
def	
  json	
  =	
  new	
  JsonBuilder()	
   representation
!

"name": "Guillaume",
json.person	
  {	
  
"age": 36,
	
  	
  	
  	
  name	
  'Guillaume'	
   [
"daughters":
Closure blocks
"Marion",
	
  	
  	
  	
  age	
  36	
  
"Erine"
delimiting
	
  	
  	
  	
  daughters	
  'Marion',	
  'Erine'	
  the
],
structure
"address": {
	
  	
  	
  	
  address	
  {	
  
"street": "1 Main Street",
	
  	
  	
  	
  	
  	
  	
  	
  street	
  '1	
  Main	
  Street'	
  
"zip": 75001,
"city":
	
  	
  	
  	
  	
  	
  	
  	
  zip	
  75001	
   "Paris"
}
	
  	
  	
  	
  	
  	
  	
  	
  city	
  'Paris'	
  
}
	
  	
  	
  	
  }	
   }

}
!57
GPath expressions
• GPath expressions are like XPath 

but for an object graph
import	
  groovy.json.*	
  
!

def	
  url	
  =	
  

	
  	
  "https://api.github.com/repos/groovy/groovy-­‐core/commits"	
  
!

def	
  commits	
  =	
  new	
  JsonSlurper().parseText(url.toURL().text)	
  
!

assert	
  commits[0].commit.author.name	
  ==	
  'Cedric	
  Champeau'

!58
GPath expressions
• GPath expressions are like XPath 

but for an object graph
import	
  groovy.json.*	
  
!

def	
  url	
  =	
  

	
  	
  "https://api.github.com/repos/groovy/groovy-­‐core/commits"	
  
!

def	
  commits	
  =	
  new	
  JsonSlurper().parseText(url.toURL().text)	
  
!

assert	
  commits[0].commit.author.name	
  ==	
  'Cedric	
  Champeau'

GPath expression
!58
GPath expressions
• GPath expressions are like XPath 

but for an object graph
import	
  groovy.json.*	
  
!

def	
  url	
  =	
  

	
  	
  "https://api.github.com/repos/groovy/groovy-­‐core/commits"	
  
!

def	
  commits	
  =	
  new	
  JsonSlurper().parseText(url.toURL().text)	
  
!

assert	
  commits[0].commit.author.name	
  ==	
  'Cedric	
  Champeau'

GPath expression
!58

Add find / findAll
into the mix
GPath expressions
• GPath expressions are like XPath 

No (un)marshalling!
but for an object graph
import	
  groovy.json.*	
  
!

def	
  url	
  =	
  

	
  	
  "https://api.github.com/repos/groovy/groovy-­‐core/commits"	
  
!

def	
  commits	
  =	
  new	
  JsonSlurper().parseText(url.toURL().text)	
  
!

assert	
  commits[0].commit.author.name	
  ==	
  'Cedric	
  Champeau'

GPath expression
!58

Add find / findAll
into the mix
Power asserts
def	
  (a,	
  b,	
  c)	
  =	
  [20,	
  30,	
  40]	
  
!

assert	
  a	
  *	
  (b	
  -­‐	
  1)	
  /	
  10	
  ==	
  3	
  *	
  c	
  /	
  2	
  +	
  1

!59
Power asserts
def	
  (a,	
  b,	
  c)	
  =	
  [20,	
  30,	
  40]	
  
!

assert	
  a	
  *	
  (b	
  -­‐	
  1)	
  /	
  10	
  ==	
  3	
  *	
  c	
  /	
  2	
  +	
  1
Assertion	
  failed:	
  	
  
!

assert	
  a	
  *	
  (b	
  -­‐	
  1)	
  /	
  10	
  ==	
  3	
  *	
  c	
  /	
  2	
  +	
  1	
  
	
  	
  	
  	
  	
  	
  	
  |	
  |	
  	
  |	
  |	
  	
  	
  	
  |	
  	
  	
  	
  |	
  	
  	
  	
  |	
  |	
  |	
  	
  	
  |	
  
	
  	
  	
  	
  	
  	
  	
  |	
  580|	
  29	
  	
  	
  58	
  	
  	
  false|	
  |	
  60	
  	
  61	
  
	
  	
  	
  	
  	
  	
  	
  20	
  	
  	
  30	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  |	
  40	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  120	
  
!

	
   at	
  script1.run(script1.groovy:3)
!59
Power asserts
def	
  (a,	
  b,	
  c)	
  =	
  [20,	
  30,	
  40]	
  
!

assert	
  a	
  *	
  (b	
  -­‐	
  1)	
  /	
  10	
  ==	
  3	
  *	
  c	
  /	
  2	
  +	
  1
Assertion	
  failed:	
  	
  
!

assert	
  a	
  *	
  (b	
  -­‐	
  1)	
  /	
  10	
  ==	
  3	
  *	
  c	
  /	
  2	
  +	
  1	
  
	
  	
  	
  	
  	
  	
  	
  |	
  |	
  	
  |	
  |	
  	
  	
  	
  |	
  	
  	
  	
  |	
  	
  	
  	
  |	
  |	
  |	
  	
  	
  |	
  
	
  	
  	
  	
  	
  	
  	
  |	
  580|	
  29	
  	
  	
  58	
  	
  	
  false|	
  |	
  60	
  	
  61	
  
	
  	
  	
  	
  	
  	
  	
  20	
  	
  	
  30	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  |	
  40	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  120	
  
!

Invented by the Spock testing framework

	
   at	
  script1.run(script1.groovy:3)
!59
Null handling
class	
  Order	
  {	
  
	
  	
  	
  	
  LineItem	
  line	
  
}	
  
class	
  LineItem	
  {	
  
	
  	
  	
  	
  int	
  quantity	
  
	
  	
  	
  	
  Item	
  item	
  
}	
  
class	
  Item	
  {	
  
	
  	
  	
  	
  String	
  name	
  
}	
  
!

def	
  o	
  =	
  new	
  Order(	
  
	
  	
  	
  	
  line:	
  new	
  LineItem(	
  
	
  	
  	
  	
  	
  	
  	
  	
  quantity:	
  2,	
  
	
  	
  	
  	
  	
  	
  	
  	
  item:	
  null))	
  
!

println	
  o.line.item.name
!60
Null handling
class	
  Order	
  {	
  
	
  	
  	
  	
  LineItem	
  line	
  
}	
  
class	
  LineItem	
  {	
  
	
  	
  	
  	
  int	
  quantity	
  
	
  	
  	
  	
  Item	
  item	
  
}	
  
class	
  Item	
  {	
  
	
  	
  	
  	
  String	
  name	
  
}	
  
!

With Java, you only
get an NPE. No idea
where it came from!

def	
  o	
  =	
  new	
  Order(	
  
	
  	
  	
  	
  line:	
  new	
  LineItem(	
  
	
  	
  	
  	
  	
  	
  	
  	
  quantity:	
  2,	
  
	
  	
  	
  	
  	
  	
  	
  	
  item:	
  null))	
  
!

println	
  o.line.item.name
!60
Null handling
class	
  Order	
  {	
  
	
  	
  	
  	
  LineItem	
  line	
  
}	
  
class	
  LineItem	
  {	
  
	
  	
  	
  	
  int	
  quantity	
  
	
  	
  	
  	
  Item	
  item	
  
}	
  
class	
  Item	
  {	
  
	
  	
  	
  	
  String	
  name	
  
}	
  
!

With Java, you only
get an NPE. No idea
where it came from!

def	
  o	
  =	
  new	
  Order(	
  
	
  	
  	
  	
  line:	
  new	
  LineItem(	
  
	
  	
  	
  	
  	
  	
  	
  	
  quantity:	
  2,	
  
	
  	
  	
  	
  	
  	
  	
  	
  item:	
  null))	
  
!

println	
  o.line.item.name
!60

Groovy will say:
Cannot get property
‘name’ on null object
Null handling
class	
  Order	
  {	
  
	
  	
  	
  	
  LineItem	
  line	
  
}	
  
class	
  LineItem	
  {	
  
	
  	
  	
  	
  int	
  quantity	
  
	
  	
  	
  	
  Item	
  item	
  
}	
  
class	
  Item	
  {	
  
	
  	
  	
  	
  String	
  name	
  
}	
  
!

def	
  o	
  =	
  new	
  Order(	
  
	
  	
  	
  	
  line:	
  new	
  LineItem(	
  
	
  	
  	
  	
  	
  	
  	
  	
  quantity:	
  2,	
  
	
  	
  	
  	
  	
  	
  	
  	
  item:	
  null))	
  
!

println	
  o.line.item.name
!60
Null handling
class	
  Order	
  {	
  
	
  	
  	
  	
  LineItem	
  line	
  
}	
  
class	
  LineItem	
  {	
  
	
  	
  	
  	
  int	
  quantity	
  
	
  	
  	
  	
  Item	
  item	
  
}	
  
class	
  Item	
  {	
  
	
  	
  	
  	
  String	
  name	
  
}	
  

o?.line?.item?.name

!

def	
  o	
  =	
  new	
  Order(	
  
	
  	
  	
  	
  line:	
  new	
  LineItem(	
  
	
  	
  	
  	
  	
  	
  	
  	
  quantity:	
  2,	
  
	
  	
  	
  	
  	
  	
  	
  	
  item:	
  null))	
  
!

println	
  o.line.item.name
!60
Null handling
class	
  Order	
  {	
  
	
  	
  	
  	
  LineItem	
  line	
  
}	
  
class	
  LineItem	
  {	
  
	
  	
  	
  	
  int	
  quantity	
  
	
  	
  	
  	
  Item	
  item	
  
}	
  
class	
  Item	
  {	
  
	
  	
  	
  	
  String	
  name	
  
}	
  

o?.line?.item?.name

!

def	
  o	
  =	
  new	
  Order(	
  
	
  	
  	
  	
  line:	
  new	
  LineItem(	
  
	
  	
  	
  	
  	
  	
  	
  	
  quantity:	
  2,	
  
	
  	
  	
  	
  	
  	
  	
  	
  item:	
  null))	
  
!

println	
  o.line.item.name
!60

Safe navigation:
will just return
null; No NPE
What makes Groovy Groovy  - Guillaume Laforge (Pivotal)
The Truth,
the Groovy Truth!
The Truth,
the Groovy Truth!
And what if I could
customize the truth?
The Groovy Truth
assert	
  !(	
  null	
  )	
  
assert	
  !(	
  	
  ""	
  	
  )	
  
assert	
  !(	
  	
  []	
  	
  )	
  
assert	
  !(	
  	
  	
  0	
  	
  )
assert	
  new	
  Object()	
  
assert	
  "string"	
  
assert	
  [1,	
  2,	
  3]	
  
assert	
  1234
!62
The Groovy Truth
null, empty, 0-sized, zero
are coerced to false

assert	
  !(	
  null	
  )	
  
assert	
  !(	
  	
  ""	
  	
  )	
  
assert	
  !(	
  	
  []	
  	
  )	
  
assert	
  !(	
  	
  	
  0	
  	
  )

assert	
  new	
  Object()	
  
assert	
  "string"	
  
assert	
  [1,	
  2,	
  3]	
  
assert	
  1234
!62
The Groovy Truth
null, empty, 0-sized, zero
are coerced to false

assert	
  !(	
  null	
  )	
  
assert	
  !(	
  	
  ""	
  	
  )	
  
assert	
  !(	
  	
  []	
  	
  )	
  
assert	
  !(	
  	
  	
  0	
  	
  )

assert	
  new	
  Object()	
  
assert	
  "string"	
  
assert	
  [1,	
  2,	
  3]	
  
assert	
  1234
!62

true otherwise
Customizing the truth!
class	
  Account	
  {	
  
	
  	
  	
  	
  String	
  name	
  
	
  	
  	
  	
  boolean	
  disabled	
  =	
  false	
  
!

	
  	
  	
  	
  boolean	
  asBoolean()	
  {	
  !disabled	
  }	
  
}	
  
!

assert	
  	
  new	
  Account(name:	
  'current')	
  
assert	
  !new	
  Account(name:	
  'old',	
  disabled:	
  true)

!63
Customizing the truth!
class	
  Account	
  {	
  
	
  	
  	
  	
  String	
  name	
  
	
  	
  	
  	
  boolean	
  disabled	
  =	
  false	
  
!

	
  	
  	
  	
  boolean	
  asBoolean()	
  {	
  !disabled	
  }	
  
}	
  
!

assert	
  	
  new	
  Account(name:	
  'current')	
  
assert	
  !new	
  Account(name:	
  'old',	
  disabled:	
  true)

while (account), if (account), etc…
!63
?:
?:
The Elvis
operator!
Towards Elvis...

!65
Towards Elvis...
def	
  (x,	
  y)	
  =	
  ['MacBook	
  Pro',	
  'unknown']

!65
Towards Elvis...
def	
  (x,	
  y)	
  =	
  ['MacBook	
  Pro',	
  'unknown']

!65
Towards Elvis...
def	
  (x,	
  y)	
  =	
  ['MacBook	
  Pro',	
  'unknown']
if	
  (x	
  !=	
  null	
  &&	
  x.size()	
  >	
  0)	
  x	
  else	
  y

!65
Towards Elvis...
def	
  (x,	
  y)	
  =	
  ['MacBook	
  Pro',	
  'unknown']
if	
  (x	
  !=	
  null	
  &&	
  x.size()	
  >	
  0)	
  x	
  else	
  y
if	
  (x	
  &&	
  x.size())	
  x	
  else	
  y

!65
Towards Elvis...
def	
  (x,	
  y)	
  =	
  ['MacBook	
  Pro',	
  'unknown']
if	
  (x	
  !=	
  null	
  &&	
  x.size()	
  >	
  0)	
  x	
  else	
  y
if	
  (x	
  &&	
  x.size())	
  x	
  else	
  y
if	
  (x)	
  x	
  else	
  y

!65
Towards Elvis...
def	
  (x,	
  y)	
  =	
  ['MacBook	
  Pro',	
  'unknown']
if	
  (x	
  !=	
  null	
  &&	
  x.size()	
  >	
  0)	
  x	
  else	
  y
if	
  (x	
  &&	
  x.size())	
  x	
  else	
  y
if	
  (x)	
  x	
  else	
  y
x	
  ?	
  x	
  :	
  y

!65
Towards Elvis...
def	
  (x,	
  y)	
  =	
  ['MacBook	
  Pro',	
  'unknown']
if	
  (x	
  !=	
  null	
  &&	
  x.size()	
  >	
  0)	
  x	
  else	
  y
if	
  (x	
  &&	
  x.size())	
  x	
  else	
  y
if	
  (x)	
  x	
  else	
  y
x	
  ?	
  x	
  :	
  y
x	
  ?:	
  y

!65
Towards Elvis...
def	
  (x,	
  y)	
  =	
  ['MacBook	
  Pro',	
  'unknown']
if	
  (x	
  !=	
  null	
  &&	
  x.size()	
  >	
  0)	
  x	
  else	
  y
if	
  (x	
  &&	
  x.size())	
  x	
  else	
  y
if	
  (x)	
  x	
  else	
  y
x	
  ?	
  x	
  :	
  y
x	
  ?:	
  y

Null, empty, zerosized... false,
otherwise true!

!65
Towards Elvis...
def	
  (x,	
  y)	
  =	
  ['MacBook	
  Pro',	
  'unknown']
if	
  (x	
  !=	
  null	
  &&	
  x.size()	
  >	
  0)	
  x	
  else	
  y
if	
  (x	
  &&	
  x.size())	
  x	
  else	
  y
if	
  (x)	
  x	
  else	
  y
x	
  ?	
  x	
  :	
  y
x	
  ?:	
  y

Good old ternary
operator

!65

Null, empty, zerosized... false,
otherwise true!
Towards Elvis...
def	
  (x,	
  y)	
  =	
  ['MacBook	
  Pro',	
  'unknown']
if	
  (x	
  !=	
  null	
  &&	
  x.size()	
  >	
  0)	
  x	
  else	
  y
if	
  (x	
  &&	
  x.size())	
  x	
  else	
  y
if	
  (x)	
  x	
  else	
  y
x	
  ?	
  x	
  :	
  y
x	
  ?:	
  y

Elvis!

!65

Good old ternary
operator

Null, empty, zerosized... false,
otherwise true!
AST transformations
• Abstract Syntax Tree
– in memory representation of your program

before being compiled into bytecode	

!

• AST transformation == process of transforming
the AST of a program before it’s compiled	

!

• Macro-like compiler hook!

!66
Lots of AST transformations...
• Code generation	

– @ToString, @EqualsAndHashCode, @Canonical,
@TupleConstructor, @InheritConstructors,
@Category, @IndexedProperty, @Lazy, @Newify	


• Class design	

– @Delegate, @Immutable, @Memoized, 

@Singleton, @Mixin	


• Logging	

– @Log, @Log4j, @Log4j2, @Slf4j
!67
Lots of AST transformations...
• Safer scripting	

– @ConditionalInterrupt, @ThreadInterrupt,
@TimedInterupt	


• Compiler directives	

– @Field, @PackageScope, @AnnotationCollector,
@DelegatesTo, @TypeChecked, @CompileStatic,
@CompileDynamic	


• Swing patterns	

– @Bindable, @ListenerList, @Vetoable
!68
Lots of AST transformations...
• Dependencies handling	

– @Grab, @GrabConfig, @GrabExclude,
@GrabResolver	


• Test assistance	

– @NotYetImplemented, @ASTTest

!69
Immutability
• Implement immutability 

by the book	

!

– final class	

– tuple-style constructor	

– private final backing fields	

– defensive copying of collections	

– equals() and hashCode() methods	

– toString() method	

– ...
!70
Immutability
• Implement immutability 

by the book	

!

– final class	

Can be error-prone to
– tuple-style constructor	

write immutable
– private final backing fields	

classes oneself!
– defensive copying of collections	

– equals() and hashCode() methods	

– toString() method	

– ...
!70
Immutability
• A Person class with	

– a String name	

– an int age

public final class Person {!
private final String name;!
private final int age;!

!
!
!
!
!

!
}!

!71

public Person(String name, int age) {!
this.name = name;!
this.age = age;!
}!
public String getName() {!
return name;!
}!
public int getAge() {!
return age;!
}!
public int hashCode() {!
return age + 31 * name.hashCode();!
}!
public boolean equals(Object other) {!
if (other == null) {!
return false;!
}!
if (this == other) {!
return true;!
}!
if (Person.class != other.getClass()) {!
return false;!
}!
Person otherPerson = (Person)other;!
if (!name.equals(otherPerson.getName()) {!
return false;!
}!
if (age != otherPerson.getAge()) {!
return false;!
}!
return true;!
}!
public String toString() {!
return "Person(" + name + ", " + age + ")";!
}!
Immutability
• A Person class with	

– a String name	

– an int age

public final class Person {!
private final String name;!
private final int age;!

!
!
!
!
!

!
}!

!71

Damn
verbose
Java!

public Person(String name, int age) {!
this.name = name;!
this.age = age;!
}!
public String getName() {!
return name;!
}!
public int getAge() {!
return age;!
}!
public int hashCode() {!
return age + 31 * name.hashCode();!
}!
public boolean equals(Object other) {!
if (other == null) {!
return false;!
}!
if (this == other) {!
return true;!
}!
if (Person.class != other.getClass()) {!
return false;!
}!
Person otherPerson = (Person)other;!
if (!name.equals(otherPerson.getName()) {!
return false;!
}!
if (age != otherPerson.getAge()) {!
return false;!
}!
return true;!
}!
public String toString() {!
return "Person(" + name + ", " + age + ")";!
}!
Immutability
• A Person class with	

– a String name	

– an int age

Damn
verbose
Java!

public final class Person {!
private final String name;!
private final int age;!

!
!
!
!
!

public Person(String name, int age) {!
this.name = name;!
this.age = age;!
}!
public String getName() {!
return name;!
}!
public int getAge() {!
return age;!
}!
public int hashCode() {!
return age + 31 * name.hashCode();!
}!
public boolean equals(Object other) {!
if (other == null) {!
return false;!
}!
if (this == other) {!
return true;!
}!
if (Person.class != other.getClass()) {!
return false;!
}!
Person otherPerson = (Person)other;!
if (!name.equals(otherPerson.getName()) {!
return false;!
}!
if (age != otherPerson.getAge()) {!
return false;!
}!
return true;!
}!

Although it’s also a valid
Groovy program!

!
}!

!71

public String toString() {!
return "Person(" + name + ", " + age + ")";!
}!
@Immutable

import	
  groovy.transform.*	
  
!

@Immutable	
  
class	
  Person	
  {	
  
	
  	
  	
  	
  String	
  name	
  
	
  	
  	
  	
  int	
  age	
  
}
!72
Memoization
• Cache the result of previous invocations of
closures or methods with the same set 

of argument values
import	
  groovy.transform.*	
  
!

@Memoized	
  
long	
  fib(long	
  n)	
  {	
  
	
  	
  	
  	
  if	
  (n	
  ==	
  0)	
  0	
  
	
  	
  	
  	
  else	
  if	
  (n	
  ==	
  1)	
  1	
  
	
  	
  	
  	
  else	
  fib(n	
  -­‐	
  1)	
  +	
  fib(n	
  -­‐	
  2)	
  
}	
  
!

println	
  fib(40)
!73
Memoization
• Cache the result of previous invocations of
closures or methods with the same set 

of argument values
import	
  groovy.transform.*	
  

Best applied to
side-effect free
functions

!

@Memoized	
  
long	
  fib(long	
  n)	
  {	
  
	
  	
  	
  	
  if	
  (n	
  ==	
  0)	
  0	
  
	
  	
  	
  	
  else	
  if	
  (n	
  ==	
  1)	
  1	
  
	
  	
  	
  	
  else	
  fib(n	
  -­‐	
  1)	
  +	
  fib(n	
  -­‐	
  2)	
  
}	
  
!

println	
  fib(40)
!73
What makes Groovy Groovy  - Guillaume Laforge (Pivotal)
Groovy allows you
to be lazy
Groovy allows you
to be lazy

The compiler will do
the job for you
Groovy allows you
to be lazy

More concise, more
readable code

The compiler will do
the job for you
Groovy allows you
to be lazy

More concise, more
readable code

The compiler will do
the job for you

Less stuff to maintain
and worry about
@TypeChecked & @CompileStatic
• Static type checking with @TypeChecked,
throws compilation errors on...	

– typos in method and variable names	

– incompatible return types	

– wrong type assignments	

!

• Supports fine-grained type inference	

– « Least Upper Bound »	

– « Flow typing »

!75
@TypeChecked & @CompileStatic
• Static type checking with @TypeChecked,
throws compilation errors on...	

– typos in method and variable names	

– incompatible return types	

You can even extend the
– wrong type assignments	


static type checker!

!

• Supports fine-grained type inference	

– « Least Upper Bound »	

– « Flow typing »

!75
@TypeChecked & @CompileStatic
• Static type checking with @TypeChecked,
throws compilation errors on...	

– typos in method and variable names	

– incompatible return types	

You can even extend the
– wrong type assignments	

!

static type checker!

• Supports fine-grained type inference	

– « Least Upper Bound »	

– « Flow typing »
Type check DSLs or

dynamic features!
!75
@TypeChecked & @CompileStatic
!

• What is type checked can also be compiled
statically with @CompileStatic	

!

– generate the same bytecode as javac	

!

– same performance as Java

!76
Pi (π)
Fibonacci
quadrature
Java

191 ms

97 ms

3.6 s

2.x

Static

compilation

197 ms

101 ms

4.3 s

1.8
!77

Binary

trees

Primitive
optimizations

360 ms

111 ms

23.7 s

1.7

Static compilation performance

No prim.

optimizations

2590 ms 3220 ms

50.0 s
3
t
r
a
P

Superb
community!
A blossoming
Ecosystem
What makes Groovy Groovy  - Guillaume Laforge (Pivotal)
What makes Groovy Groovy  - Guillaume Laforge (Pivotal)
What makes Groovy Groovy  - Guillaume Laforge (Pivotal)
What makes Groovy Groovy  - Guillaume Laforge (Pivotal)
M
V
G
What makes Groovy Groovy  - Guillaume Laforge (Pivotal)
GVM
GVM
GROOVY
ENVIRONMENT

MANAGER
GVM: Groovy enVironment Manager
• The new kid on the block	

– http://gvmtool.net/ — @gvmtool	

!

• Manage parallel versions 

of the various ecosystem projects	

!

• Supports...	

– Groovy, Grails, Griffon, Gradle,Vert.x, Spring Boot	

!

• On Linux, MacOS, Cygwin, Solaris, FreeBSD
!86
What makes Groovy Groovy  - Guillaume Laforge (Pivotal)
I’m Spock...
I’m Spock...
...the Spock testing
framework
I’m Spock...
...the Spock testing
framework
Spock example
@Grab('org.spockframework:spock-­‐core:0.7-­‐groovy-­‐2.0')	
  
import	
  spock.lang.*	
  
!

class	
  MathSpec	
  extends	
  Specification	
  {	
  
	
  	
  	
  	
  def	
  "maximum	
  of	
  two	
  numbers"()	
  {	
  
	
  	
  	
  	
  	
  	
  expect:	
  
	
  	
  	
  	
  	
  	
  	
  	
  Math.max(a,	
  b)	
  ==	
  c	
  
!

	
  	
  	
  	
  	
  	
  where:	
  
	
  	
  	
  	
  	
  	
  	
  	
  a	
  |	
  b	
  ||	
  c	
  
	
  	
  	
  	
  	
  	
  	
  	
  1	
  |	
  3	
  ||	
  3	
  
	
  	
  	
  	
  	
  	
  	
  	
  7	
  |	
  4	
  ||	
  4	
  
	
  	
  	
  	
  	
  	
  	
  	
  0	
  |	
  0	
  ||	
  0	
  
	
  	
  	
  	
  }	
  
}
!88
Spock example

@Grab a dependency

@Grab('org.spockframework:spock-­‐core:0.7-­‐groovy-­‐2.0')	
  
import	
  spock.lang.*	
  
!

class	
  MathSpec	
  extends	
  Specification	
  {	
  
	
  	
  	
  	
  def	
  "maximum	
  of	
  two	
  numbers"()	
  {	
  
	
  	
  	
  	
  	
  	
  expect:	
  
	
  	
  	
  	
  	
  	
  	
  	
  Math.max(a,	
  b)	
  ==	
  c	
  
!

	
  	
  	
  	
  	
  	
  where:	
  
	
  	
  	
  	
  	
  	
  	
  	
  a	
  |	
  b	
  ||	
  c	
  
	
  	
  	
  	
  	
  	
  	
  	
  1	
  |	
  3	
  ||	
  3	
  
	
  	
  	
  	
  	
  	
  	
  	
  7	
  |	
  4	
  ||	
  4	
  
	
  	
  	
  	
  	
  	
  	
  	
  0	
  |	
  0	
  ||	
  0	
  
	
  	
  	
  	
  }	
  
}
!88
Spock example

@Grab a dependency

@Grab('org.spockframework:spock-­‐core:0.7-­‐groovy-­‐2.0')	
  
import	
  spock.lang.*	
  
!

class	
  MathSpec	
  extends	
  Specification	
  {	
  
	
  	
  	
  	
  def	
  "maximum	
  of	
  two	
  numbers"()	
  {	
  
	
  	
  	
  	
  	
  	
  expect:	
  
	
  	
  	
  	
  	
  	
  	
  	
  Math.max(a,	
  b)	
  ==	
  c	
  
!

	
  	
  	
  	
  	
  	
  where:	
  
	
  	
  	
  	
  	
  	
  	
  	
  a	
  |	
  b	
  ||	
  c	
  
	
  	
  	
  	
  	
  	
  	
  	
  1	
  |	
  3	
  ||	
  3	
  
	
  	
  	
  	
  	
  	
  	
  	
  7	
  |	
  4	
  ||	
  4	
  
	
  	
  	
  	
  	
  	
  	
  	
  0	
  |	
  0	
  ||	
  0	
  
	
  	
  	
  	
  }	
  
}
!88

Meaningful test
method names
Spock example

@Grab a dependency

@Grab('org.spockframework:spock-­‐core:0.7-­‐groovy-­‐2.0')	
  
import	
  spock.lang.*	
  
!

Meaningful test
method names

class	
  MathSpec	
  extends	
  Specification	
  {	
  
	
  	
  	
  	
  def	
  "maximum	
  of	
  two	
  numbers"()	
  {	
  
	
  	
  	
  	
  	
  	
  expect:	
  
	
  	
  	
  	
  	
  	
  	
  	
  Math.max(a,	
  b)	
  ==	
  c	
  
Clever use of labels
!

	
  	
  	
  	
  	
  	
  where:	
  
	
  	
  	
  	
  	
  	
  	
  	
  a	
  |	
  b	
  ||	
  c	
  
	
  	
  	
  	
  	
  	
  	
  	
  1	
  |	
  3	
  ||	
  3	
  
	
  	
  	
  	
  	
  	
  	
  	
  7	
  |	
  4	
  ||	
  4	
  
	
  	
  	
  	
  	
  	
  	
  	
  0	
  |	
  0	
  ||	
  0	
  
	
  	
  	
  	
  }	
  
}
!88

for BDD style
Spock example

@Grab a dependency

@Grab('org.spockframework:spock-­‐core:0.7-­‐groovy-­‐2.0')	
  
import	
  spock.lang.*	
  
!

Meaningful test
method names

class	
  MathSpec	
  extends	
  Specification	
  {	
  
	
  	
  	
  	
  def	
  "maximum	
  of	
  two	
  numbers"()	
  {	
  
	
  	
  	
  	
  	
  	
  expect:	
  
	
  	
  	
  	
  	
  	
  	
  	
  Math.max(a,	
  b)	
  ==	
  c	
  
Clever use of labels
!

	
  	
  	
  	
  	
  	
  where:	
  
	
  	
  	
  	
  	
  	
  	
  	
  a	
  |	
  b	
  ||	
  c	
  
	
  	
  	
  	
  	
  	
  	
  	
  1	
  |	
  3	
  ||	
  3	
  
	
  	
  	
  	
  	
  	
  	
  	
  7	
  |	
  4	
  ||	
  4	
  
	
  	
  	
  	
  	
  	
  	
  	
  0	
  |	
  0	
  ||	
  0	
  
	
  	
  	
  	
  }	
  
}
!88

for BDD style
Expression to
be asserted
Spock example

@Grab a dependency

@Grab('org.spockframework:spock-­‐core:0.7-­‐groovy-­‐2.0')	
  
import	
  spock.lang.*	
  

Meaningful test
method names

!

class	
  MathSpec	
  extends	
  Specification	
  {	
  
	
  	
  	
  	
  def	
  "maximum	
  of	
  two	
  numbers"()	
  {	
  
	
  	
  	
  	
  	
  	
  expect:	
  
	
  	
  	
  	
  	
  	
  	
  	
  Math.max(a,	
  b)	
  ==	
  c	
  
Clever use of labels

for BDD style

!

	
  	
  	
  	
  	
  	
  where:	
  
	
  	
  	
  	
  	
  	
  	
  	
  a	
  |	
  b	
  ||	
  c	
  
	
  	
  	
  	
  	
  	
  	
  	
  1	
  |	
  3	
  ||	
  3	
  
	
  	
  	
  	
  	
  	
  	
  	
  7	
  |	
  4	
  ||	
  4	
  
	
  	
  	
  	
  	
  	
  	
  	
  0	
  |	
  0	
  ||	
  0	
  
	
  	
  	
  	
  }	
  
}
!88

Cute datadriven tests!

Expression to
be asserted
What makes Groovy Groovy  - Guillaume Laforge (Pivotal)
@GrabResolver("https://oss.jfrog.org/artifactory/repo")	
  
@Grab("org.ratpack-­‐framework:ratpack-­‐groovy:0.9.0-­‐SNAPSHOT")	
  
import	
  static	
  org.ratpackframework.groovy.RatpackScript.ratpack	
  
import	
  static	
  org.ratpackframework.groovy.Template.groovyTemplate	
  

!
ratpack	
  {	
  
	
  	
  	
  	
  handlers	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  get	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  response.send	
  "Welcome!"	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  

!
	
  	
  	
  	
  	
  	
  	
  	
  get("date")	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  render	
  groovyTemplate("date.html")	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  

!
	
  	
  	
  	
  	
  	
  	
  	
  assets	
  "public"	
  
	
  	
  	
  	
  }	
  
}
@GrabResolver("https://oss.jfrog.org/artifactory/repo")	
  
@Grab("org.ratpack-­‐framework:ratpack-­‐groovy:0.9.0-­‐SNAPSHOT")	
  
import	
  static	
  org.ratpackframework.groovy.RatpackScript.ratpack	
  
import	
  static	
  org.ratpackframework.groovy.Template.groovyTemplate	
  

!
ratpack	
  {	
  
	
  	
  	
  	
  handlers	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  get	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  response.send	
  "Welcome!"	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  

Lightweight Netty-based
web app toolkit

!
	
  	
  	
  	
  	
  	
  	
  	
  get("date")	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  render	
  groovyTemplate("date.html")	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  

!
	
  	
  	
  	
  	
  	
  	
  	
  assets	
  "public"	
  
	
  	
  	
  	
  }	
  
}
Geb
• Browser automation solution	

!

• WebDriver + jQuery selectors + Groovy	

!

• Handy for	

– scripting, scraping, automation...	

– functional / web / acceptance testing	

• when integrated with JUnit, TestNG or Spock

!90
Geb — Example
import	
  geb.Browser	
  
!

Browser.drive	
  {	
  
	
  	
  	
  	
  go	
  "http://myapp.com/login"	
  
!

	
  	
  	
  	
  assert	
  $("h1").text()	
  ==	
  "Please	
  Login"	
  
!

	
  	
  	
  	
  $("form.login").with	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  username	
  =	
  "admin"	
  
	
  	
  	
  	
  	
  	
  	
  	
  password	
  =	
  "password"	
  
	
  	
  	
  	
  	
  	
  	
  	
  login().click()	
  
	
  	
  	
  	
  }	
  
!

	
  	
  	
  	
  assert	
  $("h1").text()	
  ==	
  

	
  	
  	
  	
  	
  	
  	
  	
  "Admin	
  Section"	
  
}	
  

!91
Geb — Example

Drive the browser
to this site

import	
  geb.Browser	
  
!

Browser.drive	
  {	
  
	
  	
  	
  	
  go	
  "http://myapp.com/login"	
  
!

	
  	
  	
  	
  assert	
  $("h1").text()	
  ==	
  "Please	
  Login"	
  
!

	
  	
  	
  	
  $("form.login").with	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  username	
  =	
  "admin"	
  
	
  	
  	
  	
  	
  	
  	
  	
  password	
  =	
  "password"	
  
	
  	
  	
  	
  	
  	
  	
  	
  login().click()	
  
	
  	
  	
  	
  }	
  
!

	
  	
  	
  	
  assert	
  $("h1").text()	
  ==	
  

	
  	
  	
  	
  	
  	
  	
  	
  "Admin	
  Section"	
  
}	
  

!91
Geb — Example

Drive the browser
to this site

import	
  geb.Browser	
  
!

Browser.drive	
  {	
  
	
  	
  	
  	
  go	
  "http://myapp.com/login"	
  

Check the content
of the title

!

	
  	
  	
  	
  assert	
  $("h1").text()	
  ==	
  "Please	
  Login"	
  
!

	
  	
  	
  	
  $("form.login").with	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  username	
  =	
  "admin"	
  
	
  	
  	
  	
  	
  	
  	
  	
  password	
  =	
  "password"	
  
	
  	
  	
  	
  	
  	
  	
  	
  login().click()	
  
	
  	
  	
  	
  }	
  
!

	
  	
  	
  	
  assert	
  $("h1").text()	
  ==	
  

	
  	
  	
  	
  	
  	
  	
  	
  "Admin	
  Section"	
  
}	
  

!91
Geb — Example

Drive the browser
to this site

import	
  geb.Browser	
  
!

Browser.drive	
  {	
  
	
  	
  	
  	
  go	
  "http://myapp.com/login"	
  

Check the content
of the title

!

	
  	
  	
  	
  assert	
  $("h1").text()	
  ==	
  "Please	
  Login"	
  
!

	
  	
  	
  	
  $("form.login").with	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  username	
  =	
  "admin"	
  
	
  	
  	
  	
  	
  	
  	
  	
  password	
  =	
  "password"	
  
	
  	
  	
  	
  	
  	
  	
  	
  login().click()	
  
	
  	
  	
  	
  }	
  
!

	
  	
  	
  	
  assert	
  $("h1").text()	
  ==	
  

	
  	
  	
  	
  	
  	
  	
  	
  "Admin	
  Section"	
  
}	
  

!91

Find & fill in
the form
Geb — Example

Drive the browser
to this site

import	
  geb.Browser	
  
!

Browser.drive	
  {	
  
	
  	
  	
  	
  go	
  "http://myapp.com/login"	
  

Check the content
of the title

!

	
  	
  	
  	
  assert	
  $("h1").text()	
  ==	
  "Please	
  Login"	
  
!

	
  	
  	
  	
  $("form.login").with	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  username	
  =	
  "admin"	
  
	
  	
  	
  	
  	
  	
  	
  	
  password	
  =	
  "password"	
  
	
  	
  	
  	
  	
  	
  	
  	
  login().click()	
  
	
  	
  	
  	
  }	
  
!

	
  	
  	
  	
  assert	
  $("h1").text()	
  ==	
  

	
  	
  	
  	
  	
  	
  	
  	
  "Admin	
  Section"	
  
}	
  

!91

Find & fill in
the form
Submit the
form
Geb — Example

Drive the browser
to this site

import	
  geb.Browser	
  
!

Browser.drive	
  {	
  
	
  	
  	
  	
  go	
  "http://myapp.com/login"	
  

Check the content
of the title

!

	
  	
  	
  	
  assert	
  $("h1").text()	
  ==	
  "Please	
  Login"	
  
!

	
  	
  	
  	
  $("form.login").with	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  username	
  =	
  "admin"	
  
	
  	
  	
  	
  	
  	
  	
  	
  password	
  =	
  "password"	
  
	
  	
  	
  	
  	
  	
  	
  	
  login().click()	
  
	
  	
  	
  	
  }	
  
!

	
  	
  	
  	
  assert	
  $("h1").text()	
  ==	
  

	
  	
  	
  	
  	
  	
  	
  	
  "Admin	
  Section"	
  
}	
  

Find & fill in
the form
Submit the
form

In the admin section, yeah!
!91
Geb — With page objects and Spock
import	
  geb.spock.GebSpec	
  

!

class	
  GoogleWikipediaSpec	
  extends	
  GebSpec	
  {	
  

!

	
  	
  	
  	
  def	
  "first	
  result	
  for	
  wikipedia	
  search	
  should	
  be	
  wikipedia"()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  given:	
  
	
  	
  	
  	
  	
  	
  	
  	
  to	
  GoogleHomePage	
  

!

	
  	
  	
  	
  	
  	
  	
  	
  expect:	
  
	
  	
  	
  	
  	
  	
  	
  	
  at	
  GoogleHomePage	
  

!

	
  	
  	
  	
  	
  	
  	
  	
  when:	
  
	
  	
  	
  	
  	
  	
  	
  	
  search.field.value("wikipedia")	
  

!

	
  	
  	
  	
  	
  	
  	
  	
  then:	
  
	
  	
  	
  	
  	
  	
  	
  	
  waitFor	
  {	
  at	
  GoogleResultsPage	
  }	
  

!

	
  	
  	
  	
  	
  	
  	
  	
  and:	
  
	
  	
  	
  	
  	
  	
  	
  	
  firstResultLink.text()	
  ==	
  "Wikipedia"	
  

!

	
  	
  	
  	
  	
  	
  	
  	
  when:	
  
	
  	
  	
  	
  	
  	
  	
  	
  firstResultLink.click()	
  

!

	
  	
  	
  	
  	
  	
  	
  	
  then:	
  
	
  	
  	
  	
  	
  	
  	
  	
  waitFor	
  {	
  at	
  WikipediaPage	
  }	
  
	
  	
  	
  	
  }	
  
}

!92
Geb — With page objects and Spock
import	
  geb.spock.GebSpec	
  

!

With page objects
	
  	
  	
  	
  def	
  "first	
  result	
  for	
  wikipedia	
  search	
  should	
  be	
  wikipedia"()	
  {	
  
class	
  GoogleWikipediaSpec	
  extends	
  GebSpec	
  {	
  

!

	
  	
  	
  	
  	
  	
  	
  	
  given:	
  
	
  	
  	
  	
  	
  	
  	
  	
  to	
  GoogleHomePage	
  

!

	
  	
  	
  	
  	
  	
  	
  	
  expect:	
  
	
  	
  	
  	
  	
  	
  	
  	
  at	
  GoogleHomePage	
  

!

	
  	
  	
  	
  	
  	
  	
  	
  when:	
  
	
  	
  	
  	
  	
  	
  	
  	
  search.field.value("wikipedia")	
  

!

	
  	
  	
  	
  	
  	
  	
  	
  then:	
  
	
  	
  	
  	
  	
  	
  	
  	
  waitFor	
  {	
  at	
  GoogleResultsPage	
  }	
  

!

	
  	
  	
  	
  	
  	
  	
  	
  and:	
  
	
  	
  	
  	
  	
  	
  	
  	
  firstResultLink.text()	
  ==	
  "Wikipedia"	
  

!

	
  	
  	
  	
  	
  	
  	
  	
  when:	
  
	
  	
  	
  	
  	
  	
  	
  	
  firstResultLink.click()	
  

!

	
  	
  	
  	
  	
  	
  	
  	
  then:	
  
	
  	
  	
  	
  	
  	
  	
  	
  waitFor	
  {	
  at	
  WikipediaPage	
  }	
  
	
  	
  	
  	
  }	
  
}

!92
Geb — With page objects and Spock
import	
  geb.spock.GebSpec	
  

!

With page objects
	
  	
  	
  	
  def	
  "first	
  result	
  for	
  wikipedia	
  search	
  should	
  be	
  wikipedia"()	
  {	
  
class	
  GoogleWikipediaSpec	
  extends	
  GebSpec	
  {	
  

!

	
  	
  	
  	
  	
  	
  	
  	
  given:	
  
	
  	
  	
  	
  	
  	
  	
  	
  to	
  GoogleHomePage	
  

!

	
  	
  	
  	
  	
  	
  	
  	
  expect:	
  
	
  	
  	
  	
  	
  	
  	
  	
  at	
  GoogleHomePage	
  

BDD style: given/when/then

!

	
  	
  	
  	
  	
  	
  	
  	
  when:	
  
	
  	
  	
  	
  	
  	
  	
  	
  search.field.value("wikipedia")	
  

!

	
  	
  	
  	
  	
  	
  	
  	
  then:	
  
	
  	
  	
  	
  	
  	
  	
  	
  waitFor	
  {	
  at	
  GoogleResultsPage	
  }	
  

!

	
  	
  	
  	
  	
  	
  	
  	
  and:	
  
	
  	
  	
  	
  	
  	
  	
  	
  firstResultLink.text()	
  ==	
  "Wikipedia"	
  

!

	
  	
  	
  	
  	
  	
  	
  	
  when:	
  
	
  	
  	
  	
  	
  	
  	
  	
  firstResultLink.click()	
  

!

	
  	
  	
  	
  	
  	
  	
  	
  then:	
  
	
  	
  	
  	
  	
  	
  	
  	
  waitFor	
  {	
  at	
  WikipediaPage	
  }	
  
	
  	
  	
  	
  }	
  
}

!92
Geb — With page objects and Spock
import	
  geb.spock.GebSpec	
  

!

With page objects
	
  	
  	
  	
  def	
  "first	
  result	
  for	
  wikipedia	
  search	
  should	
  be	
  wikipedia"()	
  {	
  
class	
  GoogleWikipediaSpec	
  extends	
  GebSpec	
  {	
  

!

	
  	
  	
  	
  	
  	
  	
  	
  given:	
  
	
  	
  	
  	
  	
  	
  	
  	
  to	
  GoogleHomePage	
  

!

	
  	
  	
  	
  	
  	
  	
  	
  expect:	
  
	
  	
  	
  	
  	
  	
  	
  	
  at	
  GoogleHomePage	
  

BDD style: given/when/then

!

	
  	
  	
  	
  	
  	
  	
  	
  when:	
  
	
  	
  	
  	
  	
  	
  	
  	
  search.field.value("wikipedia")	
  

!

Wait for slow loading pages

	
  	
  	
  	
  	
  	
  	
  	
  then:	
  
	
  	
  	
  	
  	
  	
  	
  	
  waitFor	
  {	
  at	
  GoogleResultsPage	
  }	
  

!

	
  	
  	
  	
  	
  	
  	
  	
  and:	
  
	
  	
  	
  	
  	
  	
  	
  	
  firstResultLink.text()	
  ==	
  "Wikipedia"	
  

!

	
  	
  	
  	
  	
  	
  	
  	
  when:	
  
	
  	
  	
  	
  	
  	
  	
  	
  firstResultLink.click()	
  

!

	
  	
  	
  	
  	
  	
  	
  	
  then:	
  
	
  	
  	
  	
  	
  	
  	
  	
  waitFor	
  {	
  at	
  WikipediaPage	
  }	
  
	
  	
  	
  	
  }	
  
}

!92
4
t
r
a
P

Summary
Java’s best friend
• Java derived syntax
–Flat learning curve
–Easy to learn

• But goes beyond Java
–Concise, expressive, readable
–Fit for Domain-Specific Languages

• Seamless & transparent Java integration
–Mix & match Groovy & Java classes (joint compil.)
–No language barrier to cross
!94
Groovy’s nature
!

• Object oriented dynamic language...	

!

• But...	

– as type safe as you want it — static type checking	

– as fast as you need it — static compilation	

– as functional as you make it — closures...

!95
Groovy use cases
• Scripting tasks, build automation	

• Extension points for customizing/configuring apps	

• Business languages & Domain-Specific Languages	

• Full blown apps	

– for desktop with Griffon	

– for the web with Grails, Ratpack, Gaelyk	

– for web reactive programming with Reactor
!96
5
t
r
a
P

Thanks!
Q&A

Mais conteúdo relacionado

Destaque

Big data from the LHC commissioning: practical lessons from big science - Sim...
Big data from the LHC commissioning: practical lessons from big science - Sim...Big data from the LHC commissioning: practical lessons from big science - Sim...
Big data from the LHC commissioning: practical lessons from big science - Sim...jaxLondonConference
 
Scaling Scala to the database - Stefan Zeiger (Typesafe)
Scaling Scala to the database - Stefan Zeiger (Typesafe)Scaling Scala to the database - Stefan Zeiger (Typesafe)
Scaling Scala to the database - Stefan Zeiger (Typesafe)jaxLondonConference
 
Are you better than a coin toss? - Richard Warbuton & John Oliver (jClarity)
Are you better than a coin toss?  - Richard Warbuton & John Oliver (jClarity)Are you better than a coin toss?  - Richard Warbuton & John Oliver (jClarity)
Are you better than a coin toss? - Richard Warbuton & John Oliver (jClarity)jaxLondonConference
 
Lambda Expressions: Myths and Mistakes - Richard Warburton (jClarity)
Lambda Expressions: Myths and Mistakes - Richard Warburton (jClarity)Lambda Expressions: Myths and Mistakes - Richard Warburton (jClarity)
Lambda Expressions: Myths and Mistakes - Richard Warburton (jClarity)jaxLondonConference
 
Interactive media applications
Interactive media applicationsInteractive media applications
Interactive media applicationsNicole174
 
Are Hypermedia APIs Just Hype? - Aaron Phethean (Temenos) & Daniel Feist (Mul...
Are Hypermedia APIs Just Hype? - Aaron Phethean (Temenos) & Daniel Feist (Mul...Are Hypermedia APIs Just Hype? - Aaron Phethean (Temenos) & Daniel Feist (Mul...
Are Hypermedia APIs Just Hype? - Aaron Phethean (Temenos) & Daniel Feist (Mul...jaxLondonConference
 
The state of the art biorepository at ILRI
The state of the art biorepository at ILRIThe state of the art biorepository at ILRI
The state of the art biorepository at ILRIAbsolomon Kihara
 
Designing and Building a Graph Database Application - Ian Robinson (Neo Techn...
Designing and Building a Graph Database Application - Ian Robinson (Neo Techn...Designing and Building a Graph Database Application - Ian Robinson (Neo Techn...
Designing and Building a Graph Database Application - Ian Robinson (Neo Techn...jaxLondonConference
 
Real-world polyglot programming on the JVM - Ben Summers (ONEIS)
Real-world polyglot programming on the JVM  - Ben Summers (ONEIS)Real-world polyglot programming on the JVM  - Ben Summers (ONEIS)
Real-world polyglot programming on the JVM - Ben Summers (ONEIS)jaxLondonConference
 
What You Need to Know About Lambdas - Jamie Allen (Typesafe)
What You Need to Know About Lambdas - Jamie Allen (Typesafe)What You Need to Know About Lambdas - Jamie Allen (Typesafe)
What You Need to Know About Lambdas - Jamie Allen (Typesafe)jaxLondonConference
 
Streams and Things - Darach Ennis (Ubiquiti Networks)
Streams and Things - Darach Ennis (Ubiquiti Networks)Streams and Things - Darach Ennis (Ubiquiti Networks)
Streams and Things - Darach Ennis (Ubiquiti Networks)jaxLondonConference
 
Big Events, Mob Scale - Darach Ennis (Push Technology)
Big Events, Mob Scale - Darach Ennis (Push Technology)Big Events, Mob Scale - Darach Ennis (Push Technology)
Big Events, Mob Scale - Darach Ennis (Push Technology)jaxLondonConference
 
Legal and ethical considerations redone
Legal and ethical considerations   redoneLegal and ethical considerations   redone
Legal and ethical considerations redoneNicole174
 
Packed Objects: Fast Talking Java Meets Native Code - Steve Poole (IBM)
Packed Objects: Fast Talking Java Meets Native Code - Steve Poole (IBM)Packed Objects: Fast Talking Java Meets Native Code - Steve Poole (IBM)
Packed Objects: Fast Talking Java Meets Native Code - Steve Poole (IBM)jaxLondonConference
 
Databases and agile development - Dwight Merriman (MongoDB)
Databases and agile development - Dwight Merriman (MongoDB)Databases and agile development - Dwight Merriman (MongoDB)
Databases and agile development - Dwight Merriman (MongoDB)jaxLondonConference
 
Design is a Process, not an Artefact - Trisha Gee (MongoDB)
Design is a Process, not an Artefact - Trisha Gee (MongoDB)Design is a Process, not an Artefact - Trisha Gee (MongoDB)
Design is a Process, not an Artefact - Trisha Gee (MongoDB)jaxLondonConference
 
45 second video proposal
45 second video proposal45 second video proposal
45 second video proposalNicole174
 
How Windows 10 will change the way we use devices
How Windows 10 will change the way we use devicesHow Windows 10 will change the way we use devices
How Windows 10 will change the way we use devicesCommelius Solutions
 
A real-time architecture using Hadoop & Storm - Nathan Bijnens & Geert Van La...
A real-time architecture using Hadoop & Storm - Nathan Bijnens & Geert Van La...A real-time architecture using Hadoop & Storm - Nathan Bijnens & Geert Van La...
A real-time architecture using Hadoop & Storm - Nathan Bijnens & Geert Van La...jaxLondonConference
 

Destaque (20)

Big data from the LHC commissioning: practical lessons from big science - Sim...
Big data from the LHC commissioning: practical lessons from big science - Sim...Big data from the LHC commissioning: practical lessons from big science - Sim...
Big data from the LHC commissioning: practical lessons from big science - Sim...
 
Scaling Scala to the database - Stefan Zeiger (Typesafe)
Scaling Scala to the database - Stefan Zeiger (Typesafe)Scaling Scala to the database - Stefan Zeiger (Typesafe)
Scaling Scala to the database - Stefan Zeiger (Typesafe)
 
Are you better than a coin toss? - Richard Warbuton & John Oliver (jClarity)
Are you better than a coin toss?  - Richard Warbuton & John Oliver (jClarity)Are you better than a coin toss?  - Richard Warbuton & John Oliver (jClarity)
Are you better than a coin toss? - Richard Warbuton & John Oliver (jClarity)
 
Lambda Expressions: Myths and Mistakes - Richard Warburton (jClarity)
Lambda Expressions: Myths and Mistakes - Richard Warburton (jClarity)Lambda Expressions: Myths and Mistakes - Richard Warburton (jClarity)
Lambda Expressions: Myths and Mistakes - Richard Warburton (jClarity)
 
Interactive media applications
Interactive media applicationsInteractive media applications
Interactive media applications
 
Are Hypermedia APIs Just Hype? - Aaron Phethean (Temenos) & Daniel Feist (Mul...
Are Hypermedia APIs Just Hype? - Aaron Phethean (Temenos) & Daniel Feist (Mul...Are Hypermedia APIs Just Hype? - Aaron Phethean (Temenos) & Daniel Feist (Mul...
Are Hypermedia APIs Just Hype? - Aaron Phethean (Temenos) & Daniel Feist (Mul...
 
The state of the art biorepository at ILRI
The state of the art biorepository at ILRIThe state of the art biorepository at ILRI
The state of the art biorepository at ILRI
 
Designing and Building a Graph Database Application - Ian Robinson (Neo Techn...
Designing and Building a Graph Database Application - Ian Robinson (Neo Techn...Designing and Building a Graph Database Application - Ian Robinson (Neo Techn...
Designing and Building a Graph Database Application - Ian Robinson (Neo Techn...
 
Real-world polyglot programming on the JVM - Ben Summers (ONEIS)
Real-world polyglot programming on the JVM  - Ben Summers (ONEIS)Real-world polyglot programming on the JVM  - Ben Summers (ONEIS)
Real-world polyglot programming on the JVM - Ben Summers (ONEIS)
 
What You Need to Know About Lambdas - Jamie Allen (Typesafe)
What You Need to Know About Lambdas - Jamie Allen (Typesafe)What You Need to Know About Lambdas - Jamie Allen (Typesafe)
What You Need to Know About Lambdas - Jamie Allen (Typesafe)
 
Streams and Things - Darach Ennis (Ubiquiti Networks)
Streams and Things - Darach Ennis (Ubiquiti Networks)Streams and Things - Darach Ennis (Ubiquiti Networks)
Streams and Things - Darach Ennis (Ubiquiti Networks)
 
Big Events, Mob Scale - Darach Ennis (Push Technology)
Big Events, Mob Scale - Darach Ennis (Push Technology)Big Events, Mob Scale - Darach Ennis (Push Technology)
Big Events, Mob Scale - Darach Ennis (Push Technology)
 
Legal and ethical considerations redone
Legal and ethical considerations   redoneLegal and ethical considerations   redone
Legal and ethical considerations redone
 
Packed Objects: Fast Talking Java Meets Native Code - Steve Poole (IBM)
Packed Objects: Fast Talking Java Meets Native Code - Steve Poole (IBM)Packed Objects: Fast Talking Java Meets Native Code - Steve Poole (IBM)
Packed Objects: Fast Talking Java Meets Native Code - Steve Poole (IBM)
 
Databases and agile development - Dwight Merriman (MongoDB)
Databases and agile development - Dwight Merriman (MongoDB)Databases and agile development - Dwight Merriman (MongoDB)
Databases and agile development - Dwight Merriman (MongoDB)
 
Design is a Process, not an Artefact - Trisha Gee (MongoDB)
Design is a Process, not an Artefact - Trisha Gee (MongoDB)Design is a Process, not an Artefact - Trisha Gee (MongoDB)
Design is a Process, not an Artefact - Trisha Gee (MongoDB)
 
45 second video proposal
45 second video proposal45 second video proposal
45 second video proposal
 
How Windows 10 will change the way we use devices
How Windows 10 will change the way we use devicesHow Windows 10 will change the way we use devices
How Windows 10 will change the way we use devices
 
A real-time architecture using Hadoop & Storm - Nathan Bijnens & Geert Van La...
A real-time architecture using Hadoop & Storm - Nathan Bijnens & Geert Van La...A real-time architecture using Hadoop & Storm - Nathan Bijnens & Geert Van La...
A real-time architecture using Hadoop & Storm - Nathan Bijnens & Geert Van La...
 
Why other ppl_dont_get_it
Why other ppl_dont_get_itWhy other ppl_dont_get_it
Why other ppl_dont_get_it
 

Semelhante a What makes Groovy Groovy - Guillaume Laforge (Pivotal)

Groovy reactor grails realtime web devoxx 2013
Groovy reactor grails realtime web   devoxx 2013Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web devoxx 2013Stéphane Maldini
 
Groovy ネタ NGK 忘年会2009 ライトニングトーク
Groovy ネタ NGK 忘年会2009 ライトニングトークGroovy ネタ NGK 忘年会2009 ライトニングトーク
Groovy ネタ NGK 忘年会2009 ライトニングトークTsuyoshi Yamamoto
 
GeeCON Prague 2014 - Metaprogramming with Groovy
GeeCON Prague 2014 - Metaprogramming with GroovyGeeCON Prague 2014 - Metaprogramming with Groovy
GeeCON Prague 2014 - Metaprogramming with GroovyIván López Martín
 
ConFess Vienna 2015 - Metaprogramming with Groovy
ConFess Vienna 2015 - Metaprogramming with GroovyConFess Vienna 2015 - Metaprogramming with Groovy
ConFess Vienna 2015 - Metaprogramming with GroovyIván López Martín
 
Groovy for java developers
Groovy for java developersGroovy for java developers
Groovy for java developersPuneet Behl
 
名古屋SGGAE/J勉強会 Grails、Gaelykでハンズオン
名古屋SGGAE/J勉強会 Grails、Gaelykでハンズオン名古屋SGGAE/J勉強会 Grails、Gaelykでハンズオン
名古屋SGGAE/J勉強会 Grails、GaelykでハンズオンTsuyoshi Yamamoto
 
Lift off with Groovy 2 at JavaOne 2013
Lift off with Groovy 2 at JavaOne 2013Lift off with Groovy 2 at JavaOne 2013
Lift off with Groovy 2 at JavaOne 2013Guillaume Laforge
 
G3 Summit 2016 - Taking Advantage of Groovy Annotations
G3 Summit 2016 - Taking Advantage of Groovy AnnotationsG3 Summit 2016 - Taking Advantage of Groovy Annotations
G3 Summit 2016 - Taking Advantage of Groovy AnnotationsIván López Martín
 
Session inaugurale du Groovy User Group Paris
Session inaugurale du Groovy User Group ParisSession inaugurale du Groovy User Group Paris
Session inaugurale du Groovy User Group ParisGuillaume Laforge
 
Madrid gug - sacando partido a las transformaciones ast de groovy
Madrid gug - sacando partido a las transformaciones ast de groovyMadrid gug - sacando partido a las transformaciones ast de groovy
Madrid gug - sacando partido a las transformaciones ast de groovyIván López Martín
 
多治見IT勉強会 Groovy Grails
多治見IT勉強会 Groovy Grails多治見IT勉強会 Groovy Grails
多治見IT勉強会 Groovy GrailsTsuyoshi Yamamoto
 
Eclipsecon09 Introduction To Groovy
Eclipsecon09 Introduction To GroovyEclipsecon09 Introduction To Groovy
Eclipsecon09 Introduction To GroovyAndres Almiray
 
Meetup di GDG Italia - Leonardo Pirro - Codemotion Rome 2018
Meetup di GDG Italia - Leonardo Pirro -  Codemotion Rome 2018 Meetup di GDG Italia - Leonardo Pirro -  Codemotion Rome 2018
Meetup di GDG Italia - Leonardo Pirro - Codemotion Rome 2018 Codemotion
 
Greach 2015 AST – Groovy Transformers: More than meets the eye!
Greach 2015   AST – Groovy Transformers: More than meets the eye!Greach 2015   AST – Groovy Transformers: More than meets the eye!
Greach 2015 AST – Groovy Transformers: More than meets the eye!Iván López Martín
 
Groovy Grails DevJam Jam Session
Groovy Grails DevJam Jam SessionGroovy Grails DevJam Jam Session
Groovy Grails DevJam Jam SessionMike Hugo
 
CodeCamp Iasi 10 march 2012 - Practical Groovy
CodeCamp Iasi 10 march 2012 - Practical GroovyCodeCamp Iasi 10 march 2012 - Practical Groovy
CodeCamp Iasi 10 march 2012 - Practical GroovyCodecamp Romania
 
Hey Kotlin, How it works?
Hey Kotlin, How it works?Hey Kotlin, How it works?
Hey Kotlin, How it works?Chang W. Doh
 
Groovy for Java Developers
Groovy for Java DevelopersGroovy for Java Developers
Groovy for Java DevelopersAndres Almiray
 
Kotlin, 어떻게 동작하나요
Kotlin, 어떻게 동작하나요Kotlin, 어떻게 동작하나요
Kotlin, 어떻게 동작하나요Chang W. Doh
 

Semelhante a What makes Groovy Groovy - Guillaume Laforge (Pivotal) (20)

Groovy reactor grails realtime web devoxx 2013
Groovy reactor grails realtime web   devoxx 2013Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web devoxx 2013
 
Groovy ネタ NGK 忘年会2009 ライトニングトーク
Groovy ネタ NGK 忘年会2009 ライトニングトークGroovy ネタ NGK 忘年会2009 ライトニングトーク
Groovy ネタ NGK 忘年会2009 ライトニングトーク
 
GeeCON Prague 2014 - Metaprogramming with Groovy
GeeCON Prague 2014 - Metaprogramming with GroovyGeeCON Prague 2014 - Metaprogramming with Groovy
GeeCON Prague 2014 - Metaprogramming with Groovy
 
ConFess Vienna 2015 - Metaprogramming with Groovy
ConFess Vienna 2015 - Metaprogramming with GroovyConFess Vienna 2015 - Metaprogramming with Groovy
ConFess Vienna 2015 - Metaprogramming with Groovy
 
Groovy for java developers
Groovy for java developersGroovy for java developers
Groovy for java developers
 
The Groovy Way
The Groovy WayThe Groovy Way
The Groovy Way
 
名古屋SGGAE/J勉強会 Grails、Gaelykでハンズオン
名古屋SGGAE/J勉強会 Grails、Gaelykでハンズオン名古屋SGGAE/J勉強会 Grails、Gaelykでハンズオン
名古屋SGGAE/J勉強会 Grails、Gaelykでハンズオン
 
Lift off with Groovy 2 at JavaOne 2013
Lift off with Groovy 2 at JavaOne 2013Lift off with Groovy 2 at JavaOne 2013
Lift off with Groovy 2 at JavaOne 2013
 
G3 Summit 2016 - Taking Advantage of Groovy Annotations
G3 Summit 2016 - Taking Advantage of Groovy AnnotationsG3 Summit 2016 - Taking Advantage of Groovy Annotations
G3 Summit 2016 - Taking Advantage of Groovy Annotations
 
Session inaugurale du Groovy User Group Paris
Session inaugurale du Groovy User Group ParisSession inaugurale du Groovy User Group Paris
Session inaugurale du Groovy User Group Paris
 
Madrid gug - sacando partido a las transformaciones ast de groovy
Madrid gug - sacando partido a las transformaciones ast de groovyMadrid gug - sacando partido a las transformaciones ast de groovy
Madrid gug - sacando partido a las transformaciones ast de groovy
 
多治見IT勉強会 Groovy Grails
多治見IT勉強会 Groovy Grails多治見IT勉強会 Groovy Grails
多治見IT勉強会 Groovy Grails
 
Eclipsecon09 Introduction To Groovy
Eclipsecon09 Introduction To GroovyEclipsecon09 Introduction To Groovy
Eclipsecon09 Introduction To Groovy
 
Meetup di GDG Italia - Leonardo Pirro - Codemotion Rome 2018
Meetup di GDG Italia - Leonardo Pirro -  Codemotion Rome 2018 Meetup di GDG Italia - Leonardo Pirro -  Codemotion Rome 2018
Meetup di GDG Italia - Leonardo Pirro - Codemotion Rome 2018
 
Greach 2015 AST – Groovy Transformers: More than meets the eye!
Greach 2015   AST – Groovy Transformers: More than meets the eye!Greach 2015   AST – Groovy Transformers: More than meets the eye!
Greach 2015 AST – Groovy Transformers: More than meets the eye!
 
Groovy Grails DevJam Jam Session
Groovy Grails DevJam Jam SessionGroovy Grails DevJam Jam Session
Groovy Grails DevJam Jam Session
 
CodeCamp Iasi 10 march 2012 - Practical Groovy
CodeCamp Iasi 10 march 2012 - Practical GroovyCodeCamp Iasi 10 march 2012 - Practical Groovy
CodeCamp Iasi 10 march 2012 - Practical Groovy
 
Hey Kotlin, How it works?
Hey Kotlin, How it works?Hey Kotlin, How it works?
Hey Kotlin, How it works?
 
Groovy for Java Developers
Groovy for Java DevelopersGroovy for Java Developers
Groovy for Java Developers
 
Kotlin, 어떻게 동작하나요
Kotlin, 어떻게 동작하나요Kotlin, 어떻게 동작하나요
Kotlin, 어떻게 동작하나요
 

Mais de jaxLondonConference

Garbage Collection: the Useful Parts - Martijn Verburg & Dr John Oliver (jCla...
Garbage Collection: the Useful Parts - Martijn Verburg & Dr John Oliver (jCla...Garbage Collection: the Useful Parts - Martijn Verburg & Dr John Oliver (jCla...
Garbage Collection: the Useful Parts - Martijn Verburg & Dr John Oliver (jCla...jaxLondonConference
 
Conflict Free Replicated Data-types in Eventually Consistent Systems - Joel J...
Conflict Free Replicated Data-types in Eventually Consistent Systems - Joel J...Conflict Free Replicated Data-types in Eventually Consistent Systems - Joel J...
Conflict Free Replicated Data-types in Eventually Consistent Systems - Joel J...jaxLondonConference
 
JVM Support for Multitenant Applications - Steve Poole (IBM)
JVM Support for Multitenant Applications - Steve Poole (IBM)JVM Support for Multitenant Applications - Steve Poole (IBM)
JVM Support for Multitenant Applications - Steve Poole (IBM)jaxLondonConference
 
Introducing Vert.x 2.0 - Taking polyglot application development to the next ...
Introducing Vert.x 2.0 - Taking polyglot application development to the next ...Introducing Vert.x 2.0 - Taking polyglot application development to the next ...
Introducing Vert.x 2.0 - Taking polyglot application development to the next ...jaxLondonConference
 
How Java got its Mojo Back - James Governor (Redmonk)
How Java got its Mojo Back - James Governor (Redmonk)					How Java got its Mojo Back - James Governor (Redmonk)
How Java got its Mojo Back - James Governor (Redmonk) jaxLondonConference
 
Java Testing With Spock - Ken Sipe (Trexin Consulting)
Java Testing With Spock - Ken Sipe (Trexin Consulting)Java Testing With Spock - Ken Sipe (Trexin Consulting)
Java Testing With Spock - Ken Sipe (Trexin Consulting)jaxLondonConference
 
The Java Virtual Machine is Over - The Polyglot VM is here - Marcus Lagergren...
The Java Virtual Machine is Over - The Polyglot VM is here - Marcus Lagergren...The Java Virtual Machine is Over - The Polyglot VM is here - Marcus Lagergren...
The Java Virtual Machine is Over - The Polyglot VM is here - Marcus Lagergren...jaxLondonConference
 
Java EE 7 Platform: Boosting Productivity and Embracing HTML5 - Arun Gupta (R...
Java EE 7 Platform: Boosting Productivity and Embracing HTML5 - Arun Gupta (R...Java EE 7 Platform: Boosting Productivity and Embracing HTML5 - Arun Gupta (R...
Java EE 7 Platform: Boosting Productivity and Embracing HTML5 - Arun Gupta (R...jaxLondonConference
 
Exploring the Talend unified Big Data toolset for sentiment analysis - Ben Br...
Exploring the Talend unified Big Data toolset for sentiment analysis - Ben Br...Exploring the Talend unified Big Data toolset for sentiment analysis - Ben Br...
Exploring the Talend unified Big Data toolset for sentiment analysis - Ben Br...jaxLondonConference
 
The Curious Clojurist - Neal Ford (Thoughtworks)
The Curious Clojurist - Neal Ford (Thoughtworks)The Curious Clojurist - Neal Ford (Thoughtworks)
The Curious Clojurist - Neal Ford (Thoughtworks)jaxLondonConference
 
Run Your Java Code on Cloud Foundry - Andy Piper (Pivotal)
Run Your Java Code on Cloud Foundry - Andy Piper (Pivotal)Run Your Java Code on Cloud Foundry - Andy Piper (Pivotal)
Run Your Java Code on Cloud Foundry - Andy Piper (Pivotal)jaxLondonConference
 
Put your Java apps to sleep? Find out how - John Matthew Holt (Waratek)
Put your Java apps to sleep? Find out how - John Matthew Holt (Waratek)Put your Java apps to sleep? Find out how - John Matthew Holt (Waratek)
Put your Java apps to sleep? Find out how - John Matthew Holt (Waratek)jaxLondonConference
 
Project Lambda: Functional Programming Constructs in Java - Simon Ritter (Ora...
Project Lambda: Functional Programming Constructs in Java - Simon Ritter (Ora...Project Lambda: Functional Programming Constructs in Java - Simon Ritter (Ora...
Project Lambda: Functional Programming Constructs in Java - Simon Ritter (Ora...jaxLondonConference
 
Do You Like Coffee with Your dessert? Java and the Raspberry Pi - Simon Ritte...
Do You Like Coffee with Your dessert? Java and the Raspberry Pi - Simon Ritte...Do You Like Coffee with Your dessert? Java and the Raspberry Pi - Simon Ritte...
Do You Like Coffee with Your dessert? Java and the Raspberry Pi - Simon Ritte...jaxLondonConference
 
Little words of wisdom for the developer - Guillaume Laforge (Pivotal)
Little words of wisdom for the developer - Guillaume Laforge (Pivotal)Little words of wisdom for the developer - Guillaume Laforge (Pivotal)
Little words of wisdom for the developer - Guillaume Laforge (Pivotal)jaxLondonConference
 
Large scale, interactive ad-hoc queries over different datastores with Apache...
Large scale, interactive ad-hoc queries over different datastores with Apache...Large scale, interactive ad-hoc queries over different datastores with Apache...
Large scale, interactive ad-hoc queries over different datastores with Apache...jaxLondonConference
 
Designing Resilient Application Platforms with Apache Cassandra - Hayato Shim...
Designing Resilient Application Platforms with Apache Cassandra - Hayato Shim...Designing Resilient Application Platforms with Apache Cassandra - Hayato Shim...
Designing Resilient Application Platforms with Apache Cassandra - Hayato Shim...jaxLondonConference
 
Practical Performance: Understand the Performance of Your Application - Chris...
Practical Performance: Understand the Performance of Your Application - Chris...Practical Performance: Understand the Performance of Your Application - Chris...
Practical Performance: Understand the Performance of Your Application - Chris...jaxLondonConference
 
How Hailo fuels its growth using NoSQL storage and analytics - Dave Gardner (...
How Hailo fuels its growth using NoSQL storage and analytics - Dave Gardner (...How Hailo fuels its growth using NoSQL storage and analytics - Dave Gardner (...
How Hailo fuels its growth using NoSQL storage and analytics - Dave Gardner (...jaxLondonConference
 

Mais de jaxLondonConference (20)

Garbage Collection: the Useful Parts - Martijn Verburg & Dr John Oliver (jCla...
Garbage Collection: the Useful Parts - Martijn Verburg & Dr John Oliver (jCla...Garbage Collection: the Useful Parts - Martijn Verburg & Dr John Oliver (jCla...
Garbage Collection: the Useful Parts - Martijn Verburg & Dr John Oliver (jCla...
 
Conflict Free Replicated Data-types in Eventually Consistent Systems - Joel J...
Conflict Free Replicated Data-types in Eventually Consistent Systems - Joel J...Conflict Free Replicated Data-types in Eventually Consistent Systems - Joel J...
Conflict Free Replicated Data-types in Eventually Consistent Systems - Joel J...
 
JVM Support for Multitenant Applications - Steve Poole (IBM)
JVM Support for Multitenant Applications - Steve Poole (IBM)JVM Support for Multitenant Applications - Steve Poole (IBM)
JVM Support for Multitenant Applications - Steve Poole (IBM)
 
Introducing Vert.x 2.0 - Taking polyglot application development to the next ...
Introducing Vert.x 2.0 - Taking polyglot application development to the next ...Introducing Vert.x 2.0 - Taking polyglot application development to the next ...
Introducing Vert.x 2.0 - Taking polyglot application development to the next ...
 
How Java got its Mojo Back - James Governor (Redmonk)
How Java got its Mojo Back - James Governor (Redmonk)					How Java got its Mojo Back - James Governor (Redmonk)
How Java got its Mojo Back - James Governor (Redmonk)
 
Java Testing With Spock - Ken Sipe (Trexin Consulting)
Java Testing With Spock - Ken Sipe (Trexin Consulting)Java Testing With Spock - Ken Sipe (Trexin Consulting)
Java Testing With Spock - Ken Sipe (Trexin Consulting)
 
The Java Virtual Machine is Over - The Polyglot VM is here - Marcus Lagergren...
The Java Virtual Machine is Over - The Polyglot VM is here - Marcus Lagergren...The Java Virtual Machine is Over - The Polyglot VM is here - Marcus Lagergren...
The Java Virtual Machine is Over - The Polyglot VM is here - Marcus Lagergren...
 
Java EE 7 Platform: Boosting Productivity and Embracing HTML5 - Arun Gupta (R...
Java EE 7 Platform: Boosting Productivity and Embracing HTML5 - Arun Gupta (R...Java EE 7 Platform: Boosting Productivity and Embracing HTML5 - Arun Gupta (R...
Java EE 7 Platform: Boosting Productivity and Embracing HTML5 - Arun Gupta (R...
 
Exploring the Talend unified Big Data toolset for sentiment analysis - Ben Br...
Exploring the Talend unified Big Data toolset for sentiment analysis - Ben Br...Exploring the Talend unified Big Data toolset for sentiment analysis - Ben Br...
Exploring the Talend unified Big Data toolset for sentiment analysis - Ben Br...
 
The Curious Clojurist - Neal Ford (Thoughtworks)
The Curious Clojurist - Neal Ford (Thoughtworks)The Curious Clojurist - Neal Ford (Thoughtworks)
The Curious Clojurist - Neal Ford (Thoughtworks)
 
TDD at scale - Mash Badar (UBS)
TDD at scale - Mash Badar (UBS)TDD at scale - Mash Badar (UBS)
TDD at scale - Mash Badar (UBS)
 
Run Your Java Code on Cloud Foundry - Andy Piper (Pivotal)
Run Your Java Code on Cloud Foundry - Andy Piper (Pivotal)Run Your Java Code on Cloud Foundry - Andy Piper (Pivotal)
Run Your Java Code on Cloud Foundry - Andy Piper (Pivotal)
 
Put your Java apps to sleep? Find out how - John Matthew Holt (Waratek)
Put your Java apps to sleep? Find out how - John Matthew Holt (Waratek)Put your Java apps to sleep? Find out how - John Matthew Holt (Waratek)
Put your Java apps to sleep? Find out how - John Matthew Holt (Waratek)
 
Project Lambda: Functional Programming Constructs in Java - Simon Ritter (Ora...
Project Lambda: Functional Programming Constructs in Java - Simon Ritter (Ora...Project Lambda: Functional Programming Constructs in Java - Simon Ritter (Ora...
Project Lambda: Functional Programming Constructs in Java - Simon Ritter (Ora...
 
Do You Like Coffee with Your dessert? Java and the Raspberry Pi - Simon Ritte...
Do You Like Coffee with Your dessert? Java and the Raspberry Pi - Simon Ritte...Do You Like Coffee with Your dessert? Java and the Raspberry Pi - Simon Ritte...
Do You Like Coffee with Your dessert? Java and the Raspberry Pi - Simon Ritte...
 
Little words of wisdom for the developer - Guillaume Laforge (Pivotal)
Little words of wisdom for the developer - Guillaume Laforge (Pivotal)Little words of wisdom for the developer - Guillaume Laforge (Pivotal)
Little words of wisdom for the developer - Guillaume Laforge (Pivotal)
 
Large scale, interactive ad-hoc queries over different datastores with Apache...
Large scale, interactive ad-hoc queries over different datastores with Apache...Large scale, interactive ad-hoc queries over different datastores with Apache...
Large scale, interactive ad-hoc queries over different datastores with Apache...
 
Designing Resilient Application Platforms with Apache Cassandra - Hayato Shim...
Designing Resilient Application Platforms with Apache Cassandra - Hayato Shim...Designing Resilient Application Platforms with Apache Cassandra - Hayato Shim...
Designing Resilient Application Platforms with Apache Cassandra - Hayato Shim...
 
Practical Performance: Understand the Performance of Your Application - Chris...
Practical Performance: Understand the Performance of Your Application - Chris...Practical Performance: Understand the Performance of Your Application - Chris...
Practical Performance: Understand the Performance of Your Application - Chris...
 
How Hailo fuels its growth using NoSQL storage and analytics - Dave Gardner (...
How Hailo fuels its growth using NoSQL storage and analytics - Dave Gardner (...How Hailo fuels its growth using NoSQL storage and analytics - Dave Gardner (...
How Hailo fuels its growth using NoSQL storage and analytics - Dave Gardner (...
 

Último

Secure your environment with UiPath and CyberArk technologies - Session 1
Secure your environment with UiPath and CyberArk technologies - Session 1Secure your environment with UiPath and CyberArk technologies - Session 1
Secure your environment with UiPath and CyberArk technologies - Session 1DianaGray10
 
UiPath Studio Web workshop series - Day 6
UiPath Studio Web workshop series - Day 6UiPath Studio Web workshop series - Day 6
UiPath Studio Web workshop series - Day 6DianaGray10
 
Introduction to Matsuo Laboratory (ENG).pptx
Introduction to Matsuo Laboratory (ENG).pptxIntroduction to Matsuo Laboratory (ENG).pptx
Introduction to Matsuo Laboratory (ENG).pptxMatsuo Lab
 
OpenShift Commons Paris - Choose Your Own Observability Adventure
OpenShift Commons Paris - Choose Your Own Observability AdventureOpenShift Commons Paris - Choose Your Own Observability Adventure
OpenShift Commons Paris - Choose Your Own Observability AdventureEric D. Schabell
 
UiPath Platform: The Backend Engine Powering Your Automation - Session 1
UiPath Platform: The Backend Engine Powering Your Automation - Session 1UiPath Platform: The Backend Engine Powering Your Automation - Session 1
UiPath Platform: The Backend Engine Powering Your Automation - Session 1DianaGray10
 
Videogame localization & technology_ how to enhance the power of translation.pdf
Videogame localization & technology_ how to enhance the power of translation.pdfVideogame localization & technology_ how to enhance the power of translation.pdf
Videogame localization & technology_ how to enhance the power of translation.pdfinfogdgmi
 
UiPath Solutions Management Preview - Northern CA Chapter - March 22.pdf
UiPath Solutions Management Preview - Northern CA Chapter - March 22.pdfUiPath Solutions Management Preview - Northern CA Chapter - March 22.pdf
UiPath Solutions Management Preview - Northern CA Chapter - March 22.pdfDianaGray10
 
UiPath Studio Web workshop series - Day 8
UiPath Studio Web workshop series - Day 8UiPath Studio Web workshop series - Day 8
UiPath Studio Web workshop series - Day 8DianaGray10
 
UiPath Studio Web workshop series - Day 7
UiPath Studio Web workshop series - Day 7UiPath Studio Web workshop series - Day 7
UiPath Studio Web workshop series - Day 7DianaGray10
 
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...DianaGray10
 
AI You Can Trust - Ensuring Success with Data Integrity Webinar
AI You Can Trust - Ensuring Success with Data Integrity WebinarAI You Can Trust - Ensuring Success with Data Integrity Webinar
AI You Can Trust - Ensuring Success with Data Integrity WebinarPrecisely
 
Cybersecurity Workshop #1.pptx
Cybersecurity Workshop #1.pptxCybersecurity Workshop #1.pptx
Cybersecurity Workshop #1.pptxGDSC PJATK
 
Building AI-Driven Apps Using Semantic Kernel.pptx
Building AI-Driven Apps Using Semantic Kernel.pptxBuilding AI-Driven Apps Using Semantic Kernel.pptx
Building AI-Driven Apps Using Semantic Kernel.pptxUdaiappa Ramachandran
 
IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019
IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019
IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019IES VE
 
Anypoint Code Builder , Google Pub sub connector and MuleSoft RPA
Anypoint Code Builder , Google Pub sub connector and MuleSoft RPAAnypoint Code Builder , Google Pub sub connector and MuleSoft RPA
Anypoint Code Builder , Google Pub sub connector and MuleSoft RPAshyamraj55
 
UiPath Community: AI for UiPath Automation Developers
UiPath Community: AI for UiPath Automation DevelopersUiPath Community: AI for UiPath Automation Developers
UiPath Community: AI for UiPath Automation DevelopersUiPathCommunity
 
9 Steps For Building Winning Founding Team
9 Steps For Building Winning Founding Team9 Steps For Building Winning Founding Team
9 Steps For Building Winning Founding TeamAdam Moalla
 
Linked Data in Production: Moving Beyond Ontologies
Linked Data in Production: Moving Beyond OntologiesLinked Data in Production: Moving Beyond Ontologies
Linked Data in Production: Moving Beyond OntologiesDavid Newbury
 
Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...
Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...
Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...Will Schroeder
 

Último (20)

Secure your environment with UiPath and CyberArk technologies - Session 1
Secure your environment with UiPath and CyberArk technologies - Session 1Secure your environment with UiPath and CyberArk technologies - Session 1
Secure your environment with UiPath and CyberArk technologies - Session 1
 
UiPath Studio Web workshop series - Day 6
UiPath Studio Web workshop series - Day 6UiPath Studio Web workshop series - Day 6
UiPath Studio Web workshop series - Day 6
 
Introduction to Matsuo Laboratory (ENG).pptx
Introduction to Matsuo Laboratory (ENG).pptxIntroduction to Matsuo Laboratory (ENG).pptx
Introduction to Matsuo Laboratory (ENG).pptx
 
OpenShift Commons Paris - Choose Your Own Observability Adventure
OpenShift Commons Paris - Choose Your Own Observability AdventureOpenShift Commons Paris - Choose Your Own Observability Adventure
OpenShift Commons Paris - Choose Your Own Observability Adventure
 
UiPath Platform: The Backend Engine Powering Your Automation - Session 1
UiPath Platform: The Backend Engine Powering Your Automation - Session 1UiPath Platform: The Backend Engine Powering Your Automation - Session 1
UiPath Platform: The Backend Engine Powering Your Automation - Session 1
 
Videogame localization & technology_ how to enhance the power of translation.pdf
Videogame localization & technology_ how to enhance the power of translation.pdfVideogame localization & technology_ how to enhance the power of translation.pdf
Videogame localization & technology_ how to enhance the power of translation.pdf
 
UiPath Solutions Management Preview - Northern CA Chapter - March 22.pdf
UiPath Solutions Management Preview - Northern CA Chapter - March 22.pdfUiPath Solutions Management Preview - Northern CA Chapter - March 22.pdf
UiPath Solutions Management Preview - Northern CA Chapter - March 22.pdf
 
UiPath Studio Web workshop series - Day 8
UiPath Studio Web workshop series - Day 8UiPath Studio Web workshop series - Day 8
UiPath Studio Web workshop series - Day 8
 
UiPath Studio Web workshop series - Day 7
UiPath Studio Web workshop series - Day 7UiPath Studio Web workshop series - Day 7
UiPath Studio Web workshop series - Day 7
 
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...
 
20230104 - machine vision
20230104 - machine vision20230104 - machine vision
20230104 - machine vision
 
AI You Can Trust - Ensuring Success with Data Integrity Webinar
AI You Can Trust - Ensuring Success with Data Integrity WebinarAI You Can Trust - Ensuring Success with Data Integrity Webinar
AI You Can Trust - Ensuring Success with Data Integrity Webinar
 
Cybersecurity Workshop #1.pptx
Cybersecurity Workshop #1.pptxCybersecurity Workshop #1.pptx
Cybersecurity Workshop #1.pptx
 
Building AI-Driven Apps Using Semantic Kernel.pptx
Building AI-Driven Apps Using Semantic Kernel.pptxBuilding AI-Driven Apps Using Semantic Kernel.pptx
Building AI-Driven Apps Using Semantic Kernel.pptx
 
IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019
IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019
IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019
 
Anypoint Code Builder , Google Pub sub connector and MuleSoft RPA
Anypoint Code Builder , Google Pub sub connector and MuleSoft RPAAnypoint Code Builder , Google Pub sub connector and MuleSoft RPA
Anypoint Code Builder , Google Pub sub connector and MuleSoft RPA
 
UiPath Community: AI for UiPath Automation Developers
UiPath Community: AI for UiPath Automation DevelopersUiPath Community: AI for UiPath Automation Developers
UiPath Community: AI for UiPath Automation Developers
 
9 Steps For Building Winning Founding Team
9 Steps For Building Winning Founding Team9 Steps For Building Winning Founding Team
9 Steps For Building Winning Founding Team
 
Linked Data in Production: Moving Beyond Ontologies
Linked Data in Production: Moving Beyond OntologiesLinked Data in Production: Moving Beyond Ontologies
Linked Data in Production: Moving Beyond Ontologies
 
Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...
Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...
Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...
 

What makes Groovy Groovy - Guillaume Laforge (Pivotal)

  • 1. What makes Groovy groovy? Guillaume Laforge 
 @glaforge
  • 6. Simplify the life of (Java) developers
  • 8. Groovy as a Java superset
  • 9. Groovy as a Java superset It’s so easy to learn!
  • 13. class  MathSpec  extends  Specification  {          def  "maximum  of  two  numbers"()  {              expect:                  Math.max(a,  b)  ==  c   !            where:                  a  |  b  ||  c                  1  |  3  ||  3                  7  |  4  ||  4                  0  |  0  ||  0          }   }
  • 15. As safe and fast as Java with static type checking & compilation
  • 16. As safe and fast as Java with static type checking & compilation
  • 18. new  MarkupBuilder().html  {          head  {                  title  "The  Script  Bowl"          }   !        body  {                  div(class:  "banner")  {                          p  "Groovy  rocks!"                  }          }   }
  • 20. move  forward  at  3.km/h Expressive, Concise, Readable
  • 23. Speaking of conciseness... A full Spring app in the span of a tweet! @RestController   class  App  {          @RequestMapping("/")          String  home()  {  "Hello  World!"  }   }
  • 27. Great for scripting Fit for DomainSpecific Languages
  • 28. Great for scripting Fit for DomainSpecific Languages Most seamless integration & interoperability wih java!
  • 34. Most Java code is also valid Groovy code!
  • 35. Most Java code is also valid Groovy code! Any Java developer is a Groovy developer!
  • 39. Scripts versus Classes public  class  Main  {          public  static  void  main(String[]  args)  {                  System.out.println("Hello");          }   } vs !18
  • 40. Scripts versus Classes public  class  Main  {          public  static  void  main(String[]  args)  {                  System.out.println("Hello");          }   } vs println  "Hello" !18
  • 47. Optional... public  class  Greeter  {          private  String  owner;   !        public  String  getOwner()  {                  return  owner;          }   !        public  void  setOwner(String  owner)  {                  this.owner  =  owner;          }   !        public  String  greet(String  name)  {                  return  "Hello  "  +  name  +  ",  I  am  "  +  owner;          }   }   ! Greeter  greeter  =  new  Greeter();   greeter.setOwner("Guillaume");   ! System.out.println(greeter.greet("Marion")); !20
  • 48. Optional... Semicolons public  class  Greeter  {          private  String  owner;   !        public  String  getOwner()  {                  return  owner;          }   !        public  void  setOwner(String  owner)  {                  this.owner  =  owner;          }   !        public  String  greet(String  name)  {                  return  "Hello  "  +  name  +  ",  I  am  "  +  owner;          }   }   ! Greeter  greeter  =  new  Greeter();   greeter.setOwner("Guillaume");   ! System.out.println(greeter.greet("Marion")); !20
  • 49. Optional... public  class  Greeter  {          private  String  owner   !        public  String  getOwner()  {                  return  owner          }   !        public  void  setOwner(String  owner)  {                  this.owner  =  owner          }   !        public  String  greet(String  name)  {                  return  "Hello  "  +  name  +  ",  I  am  "  +  owner          }   }   ! Greeter  greeter  =  new  Greeter()   greeter.setOwner("Guillaume")   ! System.out.println(greeter.greet("Marion")) !21
  • 50. Optional... public  class  Greeter  {          private  String  owner   !        public  String  getOwner()  {                  return  owner          }   !        public  void  setOwner(String  owner)  {                  this.owner  =  owner          }   !        public  String  greet(String  name)  {                  return  "Hello  "  +  name  +  ",  I  am  "  +  owner          }   }   ! Greeter  greeter  =  new  Greeter()   greeter.setOwner("Guillaume")   ! System.out.println(greeter.greet("Marion")) !22
  • 51. Optional... public  class  Greeter  {          private  String  owner   !        public  String  getOwner()  {                  return  owner          }   !        public  void  setOwner(String  owner)  {                  this.owner  =  owner          }   !        public  String  greet(String  name)  {                  return  "Hello  "  +  name  +  ",  I  am  "  +  owner          }   }   ! Greeter  greeter  =  new  Greeter()   greeter.setOwner("Guillaume")   ! System.out.println(greeter.greet("Marion")) Parentheses !22
  • 52. Optional... public  class  Greeter  {          private  String  owner   !        public  String  getOwner()  {                  return  owner          }   !        public  void  setOwner(String  owner)  {                  this.owner  =  owner          }   !        public  String  greet(String  name)  {                  return  "Hello  "  +  name  +  ",  I  am  "  +  owner          }   }   ! Greeter  greeter  =  new  Greeter()   greeter.setOwner  "Guillaume"   ! System.out.println  greeter.greet("Marion") !23
  • 53. Optional... public  class  Greeter  {          private  String  owner   !        public  String  getOwner()  {                  return  owner          }   !        public  void  setOwner(String  owner)  {                  this.owner  =  owner          }   !        public  String  greet(String  name)  {                  return  "Hello  "  +  name  +  ",  I  am  "  +  owner          }   }   ! Greeter  greeter  =  new  Greeter()   greeter.setOwner  "Guillaume"   ! System.out.println  greeter.greet("Marion") return keyword !23
  • 54. Optional... public  class  Greeter  {          private  String  owner   !        public  String  getOwner()  {                                owner          }   !        public  void  setOwner(String  owner)  {                  this.owner  =  owner          }   !        public  String  greet(String  name)  {                                "Hello  "  +  name  +  ",  I  am  "  +  owner          }   }   ! Greeter  greeter  =  new  Greeter()   greeter.setOwner  "Guillaume"   ! System.out.println  greeter.greet("Marion") !24
  • 55. Optional... public  class  Greeter  {          private  String  owner   !        public  String  getOwner()  {                                owner          }   !        public  void  setOwner(String  owner)  {                  this.owner  =  owner          }   !        public  String  greet(String  name)  {                                "Hello  "  +  name  +  ",  I  am  "  +  owner          }   }   ! Greeter  greeter  =  new  Greeter()   greeter.setOwner  "Guillaume"   ! System.out.println  greeter.greet("Marion") public keyword !24
  • 56. Optional...              class  Greeter  {          private  String  owner   !                      String  getOwner()  {                                owner          }   !                      void  setOwner(String  owner)  {                  this.owner  =  owner          }   !                      String  greet(String  name)  {                                "Hello  "  +  name  +  ",  I  am  "  +  owner          }   }   ! Greeter  greeter  =  new  Greeter()   greeter.setOwner  "Guillaume"   ! System.out.println  greeter.greet("Marion") !25
  • 57. Optional...              class  Greeter  {          private  String  owner   !                      String  getOwner()  {                                owner          }   !                      void  setOwner(String  owner)  {                  this.owner  =  owner          }   !                      String  greet(String  name)  {                                "Hello  "  +  name  +  ",  I  am  "  +  owner          }   }   ! Greeter  greeter  =  new  Greeter()   greeter.setOwner  "Guillaume"   ! System.out.println  greeter.greet("Marion") optional typing !25
  • 58. Optional...              class  Greeter  {          private  String  owner   !                      String  getOwner()  {                                owner          }   !                      void  setOwner(String  owner)  {                  this.owner  =  owner          }   !                      String  greet(String  name)  {                                "Hello  "  +  name  +  ",  I  am  "  +  owner          }   }   ! def          greeter  =  new  Greeter()   greeter.setOwner  "Guillaume"   ! System.out.println  greeter.greet("Marion") !26
  • 59. Optional...              class  Greeter  {          private  String  owner   !                      String  getOwner()  {                                owner          }   !                      void  setOwner(String  owner)  {                  this.owner  =  owner          }   !                      String  greet(String  name)  {                                "Hello  "  +  name  +  ",  I  am  "  +  owner          }   }   ! def          greeter  =  new  Greeter()   greeter.setOwner  "Guillaume"   ! System.out.println  greeter.greet("Marion") handy println shortcut !26
  • 60. Optional...              class  Greeter  {          private  String  owner   !                      String  getOwner()  {                                owner          }   !                      void  setOwner(String  owner)  {                  this.owner  =  owner          }   !                      String  greet(String  name)  {                                "Hello  "  +  name  +  ",  I  am  "  +  owner          }   }   ! def          greeter  =  new  Greeter()   greeter.setOwner  "Guillaume"   !                      println  greeter.greet("Marion") !27
  • 61. Optional... verbose Java properties!              class  Greeter  {          private  String  owner   !                      String  getOwner()  {                                owner          }   !                      void  setOwner(String  owner)  {                  this.owner  =  owner          }   !                      String  greet(String  name)  {                                "Hello  "  +  name  +  ",  I  am  "  +  owner          }   }   ! def          greeter  =  new  Greeter()   greeter.setOwner  "Guillaume"   !                      println  greeter.greet("Marion") !27
  • 62. Optional...              class  Greeter  {                          String  owner   ! ! ! ! ! ! ! ! !                      String  greet(String  name)  {                                "Hello  "  +  name  +  ",  I  am  "  +  owner          }   }   ! def          greeter  =  new  Greeter()   greeter.setOwner  "Guillaume"   !                      println  greeter.greet("Marion") !28
  • 63. Optional...              class  Greeter  {                          String  owner   ! ! ! ! ! ! ! ! !                      String  greet(String  name)  {                                "Hello  "  +  name  +  ",  I  am  "  +  owner          }   }   ! def          greeter  =  new  Greeter()   greeter.setOwner  "Guillaume"   !                      println  greeter.greet("Marion") Property notation !28
  • 64. Optional...              class  Greeter  {                          String  owner   ! ! ! ! ! ! ! ! !                      String  greet(String  name)  {                                "Hello  "  +  name  +  ",  I  am  "  +  owner          }   }   ! def          greeter  =  new  Greeter()   greeter.owner        "Guillaume"   !                      println  greeter.greet("Marion") !29
  • 65. Optional...              class  Greeter  {                          String  owner   ! ! ! ! ! ! ! ! !                      String  greet(String  name)  {                                "Hello  "  +  name  +  ",  I  am  "  +  owner          }   }   ! def          greeter  =  new  Greeter()   greeter.owner        "Guillaume"   !                      println  greeter.greet("Marion") Named argument constructor !29
  • 66. Optional...              class  Greeter  {                          String  owner   ! ! ! ! ! ! ! ! !                      String  greet(String  name)  {                                "Hello  "  +  name  +  ",  I  am  "  +  owner          }   }   ! def          greeter  =  new  Greeter(owner:  "Guillaume")   ! !                      println  greeter.greet("Marion") !30
  • 67. Optional...              class  Greeter  {                          String  owner   ! ! ! ! ! ! ! ! !                      String  greet(String  name)  {                                "Hello  "  +  name  +  ",  I  am  "  +  owner          }   }   ! def          greeter  =  new  Greeter(owner:  "Guillaume")   ! !                      println  greeter.greet("Marion") Interpolated strings! (aka GStrings) !30
  • 68. Optional...              class  Greeter  {                          String  owner   ! ! ! ! ! ! ! ! !                      String  greet(String  name)  {                                "Hello  ${name},  I  am  ${owner}"          }   }   ! def          greeter  =  new  Greeter(owner:  "Guillaume")   ! !                      println  greeter.greet("Marion") !31
  • 69. Optional...              class  Greeter  {                          String  owner   ! ! ! ! ! ! ! ! !                      String  greet(String  name)  {                                "Hello  ${name},  I  am  ${owner}"          }   }   ! def          greeter  =  new  Greeter(owner:  "Guillaume")   ! !                      println  greeter.greet("Marion") Let’s reformat that mess of whitespace! !31
  • 70. Optional... class  Greeter  {          String  owner   !        String  greet(String  name)  {                "Hello  ${name},  I  am  ${owner}"          }   }   ! def  greeter  =  new  Greeter(owner:  "Guillaume")   ! println  greeter.greet("Marion") !32
  • 71. Optional... public  class  Greeter  {          private  String  owner;   !        public  String  getOwner()  {   class  Greeter  {                  return  owner;          String  owner          }   ! !        String  greet(String  name)  {          public  void  setOwner(String  owner)  {                "Hello  ${name},  I  am  ${owner}"                  this.owner  =  owner;          }          }   }   ! !        public  String  greet(String  name)  {   def  greeter  =  new  Greeter(owner:  "Guillaume")                  return  "Hello  "  +  name  +  ",  I  am  "  +  owner;   !        }   println  greeter.greet("Marion") }   ! Greeter  greeter  =  new  Greeter();   greeter.setOwner("Guillaume");   ! System.out.println(greeter.greet("Marion")); !32
  • 72. Optional... class  Greeter  {          String  owner   !        String  greet(String  name)  {                "Hello  ${name},  I  am  ${owner}"          }   }   ! def  greeter  =  new  Greeter(owner:  "Guillaume")   ! println  greeter.greet("Marion") !32
  • 73. Native syntax constructs //  closures   def  adder  =  {  a,  b  -­‐>  a  +  b  }   ! //  lists   def  list  =  [1,  2,  3,  4,  5]   ! //  maps   def  map  =  [a:  1,  b:  2,  c:  3]   ! //  regular  expressions   def  regex  =  ~/.*foo.*/   ! //  ranges   def  range  128..255 !33
  • 74. Closures — the basics def  adder  =  {  a,  b  -­‐>  a  +  b  }   ! assert  adder(1,  2)  ==  3   assert  adder('a',  'b')  ==  'ab' !34
  • 75. Closures — the basics Closure parameters def  adder  =  {  a,  b  -­‐>  a  +  b  }   ! assert  adder(1,  2)  ==  3   assert  adder('a',  'b')  ==  'ab' !34
  • 76. Closures — the basics Assign a function into a variable Closure parameters def  adder  =  {  a,  b  -­‐>  a  +  b  }   ! assert  adder(1,  2)  ==  3   assert  adder('a',  'b')  ==  'ab' !34
  • 77. Closures — the basics Assign a function into a variable Closure parameters def  adder  =  {  a,  b  -­‐>  a  +  b  }   ! assert  adder(1,  2)  ==  3   assert  adder('a',  'b')  ==  'ab' Short form of: adder.call(‘a’, ‘b’) !34
  • 78. Closures — the basics Assign a function into a variable Closure parameters def  adder  =  {  a,  b  -­‐>  a  +  b  }   ! assert  adder(1,  2)  ==  3   assert  adder('a',  'b')  ==  'ab' Short form of: adder.call(‘a’, ‘b’) !34 Genericity with duck typing & operator overloading
  • 79. Closures — explicit type ! def  intAdder  =  {  int  a,  int  b  -­‐>  a  +  b  }   !35
  • 80. Closures — explicit type Be explicit about the types ! def  intAdder  =  {  int  a,  int  b  -­‐>  a  +  b  }   !35
  • 81. Closures — implicit parameter def  doubler  =  {  it  *  2  }   ! assert  doubler(3)  ==  6   assert  doubler('a')  ==  'aa' !36
  • 82. Closures — implicit parameter Implicit parameter def  doubler  =  {  it  *  2  }   ! assert  doubler(3)  ==  6   assert  doubler('a')  ==  'aa' !36
  • 83. Closures — implicit parameter Implicit parameter def  doubler  =  {  it  *  2  }   ! assert  doubler(3)  ==  6   assert  doubler('a')  ==  'aa' Multiply also defined on strings !36
  • 84. Closures — variable arguments def  sum  =  {  ...  elements  -­‐>  
                                elements.sum()  }   ! assert  sum(1,  2)  ==  3   assert  sum('a',  'b',  'c')  ==  'abc' !37
  • 85. Closures — variable arguments Variable number of arguments def  sum  =  {  ...  elements  -­‐>  
                                elements.sum()  }   ! assert  sum(1,  2)  ==  3   assert  sum('a',  'b',  'c')  ==  'abc' !37
  • 86. Closures — variable arguments You can specify the type: int... Variable number of arguments def  sum  =  {  ...  elements  -­‐>  
                                elements.sum()  }   ! assert  sum(1,  2)  ==  3   assert  sum('a',  'b',  'c')  ==  'abc' !37
  • 87. Closures — default values def  mult  =  {  int  a,  int  b  =  10  -­‐>  a  *  b  }   ! assert  mult(2,  3)  ==  6   assert  mult(5)  ==  50 !38
  • 88. Closures — default values Default value def  mult  =  {  int  a,  int  b  =  10  -­‐>  a  *  b  }   ! assert  mult(2,  3)  ==  6   assert  mult(5)  ==  50 !38
  • 89. Closures — default values Default value def  mult  =  {  int  a,  int  b  =  10  -­‐>  a  *  b  }   ! assert  mult(2,  3)  ==  6   assert  mult(5)  ==  50 !38 Provided value for b
  • 90. Closures — default values Default value def  mult  =  {  int  a,  int  b  =  10  -­‐>  a  *  b  }   ! assert  mult(2,  3)  ==  6   assert  mult(5)  ==  50 Default value used for b !38 Provided value for b
  • 91. Closures — methods as functions def  logBase10  =  Math.&log10   def  printer  =  System.out.&println   ! assert  logBase10(10)  ==  1   printer  'abc' !39
  • 92. Closures — methods as functions Turn a method into a closure function def  logBase10  =  Math.&log10   def  printer  =  System.out.&println   ! assert  logBase10(10)  ==  1   printer  'abc' !39
  • 93. Closures — map / filter / reduce !40
  • 94. Closures — map / filter / reduce @groovy.transform.Immutable
 class  Person  {
        String  name
        int  age
 } !40
  • 95. Closures — map / filter / reduce @groovy.transform.Immutable
 class  Person  {
        String  name
        int  age
 } !40
  • 96. Closures — map / filter / reduce @groovy.transform.Immutable
 class  Person  {
        String  name
        int  age
 } def  persons  =  [
        new  Person('Guillaume',  36),
        new  Person('Marion',  5),
        new  Person('Erine',  1)
 ] !40
  • 97. Closures — map / filter / reduce @groovy.transform.Immutable
 class  Person  {
        String  name
        int  age
 } def  persons  =  [
        new  Person('Guillaume',  36),
        new  Person('Marion',  5),
        new  Person('Erine',  1)
 ] !40
  • 98. Closures — map / filter / reduce @groovy.transform.Immutable
 class  Person  {
        String  name
        int  age
 } def  persons  =  [
        new  Person('Guillaume',  36),
        new  Person('Marion',  5),
        new  Person('Erine',  1)
 ] def  names  =
        persons.findAll  {  it.age  <  18  }
                      .collect  {  it.name.toUpperCase()  }
                      .sort()
                      .join(',  ') !40
  • 99. Closures — map / filter / reduce @groovy.transform.Immutable
 class  Person  {
        String  name
        int  age
 } def  persons  =  [
        new  Person('Guillaume',  36),
        new  Person('Marion',  5),
        new  Person('Erine',  1)
 ] def  names  =
        persons.findAll  {  it.age  <  18  }
                      .collect  {  it.name.toUpperCase()  }
                      .sort()
                      .join(',  ') !40
  • 100. Closures — map / filter / reduce @groovy.transform.Immutable
 class  Person  {
        String  name
        int  age
 } def  persons  =  [
        new  Person('Guillaume',  36),
        new  Person('Marion',  5),
        new  Person('Erine',  1)
 ] def  names  =
        persons.findAll  {  it.age  <  18  }
                      .collect  {  it.name.toUpperCase()  }
                      .sort()
                      .join(',  ') assert  names  ==  "ERINE,  MARION" !40
  • 101. Closures — map / filter / reduce @groovy.transform.Immutable
 class  Person  {
        String  name
        int  age
 } def  persons  =  [
        new  Person('Guillaume',  36),
        new  Person('Marion',  5),
        new  Person('Erine',  1)
 ] find/findAll, inject, collect, flatten, min/max, unique, reverse, collate, groupBy, any/ every, head/tail/last, count/ countBy, combinations/ permutations/subsequences/ transpose, withDefault/ withLazyDefault def  names  =
        persons.findAll  {  it.age  <  18  }
                      .collect  {  it.name.toUpperCase()  }
                      .sort()
                      .join(',  ') assert  names  ==  "ERINE,  MARION" !40
  • 102. Closures — resource handling new  File('bible.txt').withReader  {  r  -­‐>          new  File('out.txt').withWriter  {  w  -­‐>                  r.eachLine  {  line  -­‐>                          if  (line.contains('Groovy'))                                  w  <<  line.toUpperCase()                  }          }   } !41
  • 103. Closures — resource handling Take care of properly opening / closing resources new  File('bible.txt').withReader  {  r  -­‐>          new  File('out.txt').withWriter  {  w  -­‐>                  r.eachLine  {  line  -­‐>                          if  (line.contains('Groovy'))                                  w  <<  line.toUpperCase()                  }          }   } !41
  • 104. Closures — custom control structures void  unless(boolean  cond,  Closure  c)  {          if  (!cond)  c()   }   ! unless  (10  <  9)  {          println  "less"   } !42
  • 105. Closures — custom control structures Closure as last argument void  unless(boolean  cond,  Closure  c)  {          if  (!cond)  c()   }   ! unless  (10  <  9)  {          println  "less"   } !42
  • 106. Closures — custom control structures Closure as last argument void  unless(boolean  cond,  Closure  c)  {          if  (!cond)  c()   }   ! unless  (10  <  9)  {          println  "less"   } !42 Equivalent to: unless(10<9, {...})
  • 107. Lists def  list  =  ['a',  'b',  'c']   ! list  <<  'd'   assert  list.contains('d')   ! assert  list.findAll  {  it.startsWith  'a'  }.size()  ==  1   assert  list.collect  {  it.toUpperCase()  }  
                                                              ==  ['A',  'B',  'C',  'D']   assert  list.inject('')  {  a,  b  -­‐>  a  +  b  }  ==  'abcd' !43
  • 108. Lists List definition def  list  =  ['a',  'b',  'c']   ! list  <<  'd'   assert  list.contains('d')   ! assert  list.findAll  {  it.startsWith  'a'  }.size()  ==  1   assert  list.collect  {  it.toUpperCase()  }  
                                                              ==  ['A',  'B',  'C',  'D']   assert  list.inject('')  {  a,  b  -­‐>  a  +  b  }  ==  'abcd' !43
  • 109. Lists List definition def  list  =  ['a',  'b',  'c']   ! Append an element (operator overloading) list  <<  'd'   assert  list.contains('d')   ! assert  list.findAll  {  it.startsWith  'a'  }.size()  ==  1   assert  list.collect  {  it.toUpperCase()  }  
                                                              ==  ['A',  'B',  'C',  'D']   assert  list.inject('')  {  a,  b  -­‐>  a  +  b  }  ==  'abcd' !43
  • 110. Lists List definition def  list  =  ['a',  'b',  'c']   ! Append an element (operator overloading) list  <<  'd'   assert  list.contains('d')   ! assert  list.findAll  {  it.startsWith  'a'  }.size()  ==  1   assert  list.collect  {  it.toUpperCase()  }  
                                                              ==  ['A',  'B',  'C',  'D']   assert  list.inject('')  {  a,  b  -­‐>  a  +  b  }  ==  'abcd' Functional-style map / filter / reduce with closures !43
  • 111. Maps def  map  =  [name:  'Guillaume',  age:  36]   ! map.daughters  =  ['Marion',  'Erine']   ! assert  map['daughters'].contains('Marion') !44
  • 112. Maps Map definition def  map  =  [name:  'Guillaume',  age:  36]   ! map.daughters  =  ['Marion',  'Erine']   ! assert  map['daughters'].contains('Marion') !44
  • 113. Maps Map definition def  map  =  [name:  'Guillaume',  age:  36]   ! map.daughters  =  ['Marion',  'Erine']   ! assert  map['daughters'].contains('Marion') Indexed access !44
  • 114. Maps Map definition def  map  =  [name:  'Guillaume',  age:  36]   ! map.daughters  =  ['Marion',  'Erine']   ! assert  map['daughters'].contains('Marion') Property notation access !44 Indexed access
  • 115. Regular expressions def  pattern  =  ~/.*foo.*/   ! assert  "Alibaba"  ==~  /.*(ba){2}/   ! def  matcher  =  "Superman"  =~  /([A-­‐Z][a-­‐z]+)man/   assert  matcher[0][0]  ==  'Superman'   assert  matcher[0][1]  ==  'Super'   ! '75001  Paris'.find(/(d{5})s(w)+/)  {  match,  zip,  town  -­‐>          println  "The  Zip  code  of  ${town}  is  ${zip}"   } !45
  • 116. Regular expressions Pattern def  pattern  =  ~/.*foo.*/   ! assert  "Alibaba"  ==~  /.*(ba){2}/   ! def  matcher  =  "Superman"  =~  /([A-­‐Z][a-­‐z]+)man/   assert  matcher[0][0]  ==  'Superman'   assert  matcher[0][1]  ==  'Super'   ! '75001  Paris'.find(/(d{5})s(w)+/)  {  match,  zip,  town  -­‐>          println  "The  Zip  code  of  ${town}  is  ${zip}"   } !45
  • 117. Regular expressions Pattern Match def  pattern  =  ~/.*foo.*/   ! assert  "Alibaba"  ==~  /.*(ba){2}/   ! def  matcher  =  "Superman"  =~  /([A-­‐Z][a-­‐z]+)man/   assert  matcher[0][0]  ==  'Superman'   assert  matcher[0][1]  ==  'Super'   ! '75001  Paris'.find(/(d{5})s(w)+/)  {  match,  zip,  town  -­‐>          println  "The  Zip  code  of  ${town}  is  ${zip}"   } !45
  • 118. Regular expressions Pattern Match def  pattern  =  ~/.*foo.*/   ! assert  "Alibaba"  ==~  /.*(ba){2}/   Find ! def  matcher  =  "Superman"  =~  /([A-­‐Z][a-­‐z]+)man/   assert  matcher[0][0]  ==  'Superman'   assert  matcher[0][1]  ==  'Super'   ! '75001  Paris'.find(/(d{5})s(w)+/)  {  match,  zip,  town  -­‐>          println  "The  Zip  code  of  ${town}  is  ${zip}"   } !45
  • 119. Regular expressions Pattern Match def  pattern  =  ~/.*foo.*/   ! assert  "Alibaba"  ==~  /.*(ba){2}/   Find ! def  matcher  =  "Superman"  =~  /([A-­‐Z][a-­‐z]+)man/   assert  matcher[0][0]  ==  'Superman'   assert  matcher[0][1]  ==  'Super'   ! '75001  Paris'.find(/(d{5})s(w)+/)  {  match,  zip,  town  -­‐>          println  "The  Zip  code  of  ${town}  is  ${zip}"   } Nice way to decompose the matched regions !45
  • 120. Ranges def  range  =  'a'..'z'   ! assert  range.contains('m')   assert  range.contains('z')   ! def  exclusive  =  1..<10   ! assert  !exclusive.contains(10)   ! def  reverse  =  10..0   ! assert  reverse[0]  ==  10   assert  reverse[-­‐1]  ==  0 !46
  • 121. Ranges Range def  range  =  'a'..'z'   ! assert  range.contains('m')   assert  range.contains('z')   ! def  exclusive  =  1..<10   ! assert  !exclusive.contains(10)   ! def  reverse  =  10..0   ! assert  reverse[0]  ==  10   assert  reverse[-­‐1]  ==  0 !46
  • 122. Ranges Range def  range  =  'a'..'z'   ! assert  range.contains('m')   assert  range.contains('z')   ! def  exclusive  =  1..<10   Excluded upper bound ! assert  !exclusive.contains(10)   ! def  reverse  =  10..0   ! assert  reverse[0]  ==  10   assert  reverse[-­‐1]  ==  0 !46
  • 123. Ranges Range def  range  =  'a'..'z'   ! assert  range.contains('m')   assert  range.contains('z')   ! def  exclusive  =  1..<10   Excluded upper bound ! assert  !exclusive.contains(10)   ! def  reverse  =  10..0   ! assert  reverse[0]  ==  10   assert  reverse[-­‐1]  ==  0 !46 Reverse range
  • 124. Ranges Range def  range  =  'a'..'z'   ! assert  range.contains('m')   assert  range.contains('z')   ! def  exclusive  =  1..<10   Excluded upper bound ! assert  !exclusive.contains(10)   ! def  reverse  =  10..0   Reverse range ! assert  reverse[0]  ==  10   assert  reverse[-­‐1]  ==  0 !46 Negative index count from the end
  • 125. Strings, GStrings, multiline strings def  name  =  'Groovy'   def  tmpl  =  """          Dear  Mr  ${name},          You're  the  winner  of  the  lottery!          Yours  sincerly,          Dave   """   ! assert  tmpl.toString().contains('Groovy') !47
  • 126. Strings, GStrings, multiline strings Plain java.lang.String def  name  =  'Groovy'   def  tmpl  =  """          Dear  Mr  ${name},          You're  the  winner  of  the  lottery!          Yours  sincerly,          Dave   """   ! assert  tmpl.toString().contains('Groovy') !47
  • 127. Strings, GStrings, multiline strings Plain java.lang.String def  name  =  'Groovy'   Multiline string with def  tmpl  =  """   expression interpolation        Dear  Mr  ${name},          You're  the  winner  of  the  lottery!          Yours  sincerly,          Dave   """   ! assert  tmpl.toString().contains('Groovy') !47
  • 129. Surprising numbers... System.out.println(  2.0  -­‐  1.1  ); 0.8999999999999999 !48
  • 130. Surprising numbers... System.out.println(  2.0  -­‐  1.1  ); 0.8999999999999999 !48
  • 134. BigDecimal by default! assert  2.0  -­‐  1.1  ==  0.9 assert  3  /  2  ==  1.5 !50
  • 135. BigDecimal by default! assert  2.0  -­‐  1.1  ==  0.9 assert  3  /  2  ==  1.5 One of the reasons why microbenchmarks sometimes showed Groovy to be slow... !50
  • 136. BigDecimal by default! assert  2.0  -­‐  1.1  ==  0.9 assert  3  /  2  ==  1.5 One of the reasons why microbenchmarks sometimes showed Groovy to be slow... !50 But you can use doubles & floats for performance, with ‘d’ or ‘f ’ suffixes or with explicit type
  • 139. Powerful switch / case on steroids switch(obj)  {          case  123:                  "number  123";              break          case  "abc":              "string  abc";              break          case  String:            "is  a  string";            break          case  [1,  2,  3]:      "in  list";                    break          case  ~/.*o+.*/:      "regex  match";            break          case  {  it  <  3  }:    "closure  criteria";  break          default:                    "unknown"   }
  • 140. Named arguments move  obj,  x:  3,  y:  4 !52
  • 141. Named arguments move  obj,  x:  3,  y:  4 Normal argument !52
  • 142. Named arguments move  obj,  x:  3,  y:  4 Normal argument !52 Named argument
  • 143. Named arguments move  obj,  x:  3,  y:  4 Normal argument Calls: move(Map m, Object) !52 Named argument
  • 144. Command chains • Ability to chain method calls 
 without parentheses and dots move  forward  at  3.km/h !53
  • 145. Command chains • Ability to chain method calls 
 without parentheses and dots move  forward  at  3.km/h Actually equivalent to: move(forward).at(3.getKm().div(h)) !53
  • 146. Named arguments & command chains check  that:  vodka  tastes  good !54
  • 147. Named arguments & command chains check  that:  vodka  tastes  good Will call: check(that: vodka).tastes(good) !54
  • 148. Multiple assignment & destructuring def  (a,  b)  =  ['A',  'B']   ! (a,  b)  =  [b,  a]   ! def  (int  i,  int  j)  =  [1,  2]   ! def  geocode(String  place)  {          return  [45.4,  2.3]   }   ! def  (la,  lo)  =  geocode("Paris")   ! assert  la  ==  45.4  &&  lo  ==  2.3 !55
  • 149. Multiple assignment & destructuring def  (a,  b)  =  ['A',  'B']   ! (a,  b)  =  [b,  a]   Classic « swap » ! def  (int  i,  int  j)  =  [1,  2]   ! def  geocode(String  place)  {          return  [45.4,  2.3]   }   ! def  (la,  lo)  =  geocode("Paris")   ! assert  la  ==  45.4  &&  lo  ==  2.3 !55
  • 150. Multiple assignment & destructuring def  (a,  b)  =  ['A',  'B']   ! With types (a,  b)  =  [b,  a]   Classic « swap » ! def  (int  i,  int  j)  =  [1,  2]   ! def  geocode(String  place)  {          return  [45.4,  2.3]   }   ! def  (la,  lo)  =  geocode("Paris")   ! assert  la  ==  45.4  &&  lo  ==  2.3 !55
  • 151. Multiple assignment & destructuring def  (a,  b)  =  ['A',  'B']   ! With types (a,  b)  =  [b,  a]   Classic « swap » ! def  (int  i,  int  j)  =  [1,  2]   Method returning a list ! def  geocode(String  place)  {          return  [45.4,  2.3]   }   ! def  (la,  lo)  =  geocode("Paris")   ! assert  la  ==  45.4  &&  lo  ==  2.3 !55
  • 152. Multiple assignment & destructuring def  (a,  b)  =  ['A',  'B']   ! With types (a,  b)  =  [b,  a]   Classic « swap » ! def  (int  i,  int  j)  =  [1,  2]   Method returning a list ! def  geocode(String  place)  {          return  [45.4,  2.3]   }   Destructuring ! def  (la,  lo)  =  geocode("Paris")   ! assert  la  ==  45.4  &&  lo  ==  2.3 !55
  • 153. Multiple assignment and destructuring class  Point  {          double  x,  y   !        double  getAt(int  idx)  {                  if  (idx  ==  0)  x                  else  if  (idx  ==  1)  y                  else  throw  new  Exception("Wrong  index")          }   }   ! def  (x,  y)  =  new  Point(x:  48.3,  y:  3.5)   ! assert  x  ==  48.3  &&  y  ==  3.5 !56
  • 154. Multiple assignment and destructuring class  Point  {          double  x,  y   Method signature convention: getAt(int) !        double  getAt(int  idx)  {                  if  (idx  ==  0)  x                  else  if  (idx  ==  1)  y                  else  throw  new  Exception("Wrong  index")          }   }   ! def  (x,  y)  =  new  Point(x:  48.3,  y:  3.5)   ! assert  x  ==  48.3  &&  y  ==  3.5 !56
  • 155. Multiple assignment and destructuring class  Point  {          double  x,  y   Method signature convention: getAt(int) !        double  getAt(int  idx)  {                  if  (idx  ==  0)  x                  else  if  (idx  ==  1)  y                  else  throw  new  Exception("Wrong  index")          }   }   Transparent destructuring ! def  (x,  y)  =  new  Point(x:  48.3,  y:  3.5)   ! assert  x  ==  48.3  &&  y  ==  3.5 !56
  • 156. Builders — JSON builder import  groovy.json.*   ! def  json  =  new  JsonBuilder()   json.person  {          name  'Guillaume'          age  36          daughters  'Marion',  'Erine'          address  {                  street  '1  Main  Street'                  zip  75001                  city  'Paris'          }   } !57
  • 157. Builders — JSON builder import  groovy.json.*   Hierarchical data def  json  =  new  JsonBuilder()   representation ! json.person  {          name  'Guillaume'          age  36          daughters  'Marion',  'Erine'          address  {                  street  '1  Main  Street'                  zip  75001                  city  'Paris'          }   } !57
  • 158. Builders — JSON builder import  groovy.json.*   Hierarchical data def  json  =  new  JsonBuilder()   representation ! json.person  {          name  'Guillaume'   Closure blocks        age  36   delimiting        daughters  'Marion',  'Erine'  the structure        address  {                  street  '1  Main  Street'                  zip  75001                  city  'Paris'          }   } !57
  • 159. Builders — JSON builder import  groovy.json.*   Hierarchical data { "person": { def  json  =  new  JsonBuilder()   representation ! "name": "Guillaume", json.person  {   "age": 36,        name  'Guillaume'   [ "daughters": Closure blocks "Marion",        age  36   "Erine" delimiting        daughters  'Marion',  'Erine'  the ], structure "address": {        address  {   "street": "1 Main Street",                street  '1  Main  Street'   "zip": 75001, "city":                zip  75001   "Paris" }                city  'Paris'   }        }   } } !57
  • 160. GPath expressions • GPath expressions are like XPath 
 but for an object graph import  groovy.json.*   ! def  url  =  
    "https://api.github.com/repos/groovy/groovy-­‐core/commits"   ! def  commits  =  new  JsonSlurper().parseText(url.toURL().text)   ! assert  commits[0].commit.author.name  ==  'Cedric  Champeau' !58
  • 161. GPath expressions • GPath expressions are like XPath 
 but for an object graph import  groovy.json.*   ! def  url  =  
    "https://api.github.com/repos/groovy/groovy-­‐core/commits"   ! def  commits  =  new  JsonSlurper().parseText(url.toURL().text)   ! assert  commits[0].commit.author.name  ==  'Cedric  Champeau' GPath expression !58
  • 162. GPath expressions • GPath expressions are like XPath 
 but for an object graph import  groovy.json.*   ! def  url  =  
    "https://api.github.com/repos/groovy/groovy-­‐core/commits"   ! def  commits  =  new  JsonSlurper().parseText(url.toURL().text)   ! assert  commits[0].commit.author.name  ==  'Cedric  Champeau' GPath expression !58 Add find / findAll into the mix
  • 163. GPath expressions • GPath expressions are like XPath 
 No (un)marshalling! but for an object graph import  groovy.json.*   ! def  url  =  
    "https://api.github.com/repos/groovy/groovy-­‐core/commits"   ! def  commits  =  new  JsonSlurper().parseText(url.toURL().text)   ! assert  commits[0].commit.author.name  ==  'Cedric  Champeau' GPath expression !58 Add find / findAll into the mix
  • 164. Power asserts def  (a,  b,  c)  =  [20,  30,  40]   ! assert  a  *  (b  -­‐  1)  /  10  ==  3  *  c  /  2  +  1 !59
  • 165. Power asserts def  (a,  b,  c)  =  [20,  30,  40]   ! assert  a  *  (b  -­‐  1)  /  10  ==  3  *  c  /  2  +  1 Assertion  failed:     ! assert  a  *  (b  -­‐  1)  /  10  ==  3  *  c  /  2  +  1                |  |    |  |        |        |        |  |  |      |                |  580|  29      58      false|  |  60    61                20      30                              |  40                                                            120   !   at  script1.run(script1.groovy:3) !59
  • 166. Power asserts def  (a,  b,  c)  =  [20,  30,  40]   ! assert  a  *  (b  -­‐  1)  /  10  ==  3  *  c  /  2  +  1 Assertion  failed:     ! assert  a  *  (b  -­‐  1)  /  10  ==  3  *  c  /  2  +  1                |  |    |  |        |        |        |  |  |      |                |  580|  29      58      false|  |  60    61                20      30                              |  40                                                            120   ! Invented by the Spock testing framework   at  script1.run(script1.groovy:3) !59
  • 167. Null handling class  Order  {          LineItem  line   }   class  LineItem  {          int  quantity          Item  item   }   class  Item  {          String  name   }   ! def  o  =  new  Order(          line:  new  LineItem(                  quantity:  2,                  item:  null))   ! println  o.line.item.name !60
  • 168. Null handling class  Order  {          LineItem  line   }   class  LineItem  {          int  quantity          Item  item   }   class  Item  {          String  name   }   ! With Java, you only get an NPE. No idea where it came from! def  o  =  new  Order(          line:  new  LineItem(                  quantity:  2,                  item:  null))   ! println  o.line.item.name !60
  • 169. Null handling class  Order  {          LineItem  line   }   class  LineItem  {          int  quantity          Item  item   }   class  Item  {          String  name   }   ! With Java, you only get an NPE. No idea where it came from! def  o  =  new  Order(          line:  new  LineItem(                  quantity:  2,                  item:  null))   ! println  o.line.item.name !60 Groovy will say: Cannot get property ‘name’ on null object
  • 170. Null handling class  Order  {          LineItem  line   }   class  LineItem  {          int  quantity          Item  item   }   class  Item  {          String  name   }   ! def  o  =  new  Order(          line:  new  LineItem(                  quantity:  2,                  item:  null))   ! println  o.line.item.name !60
  • 171. Null handling class  Order  {          LineItem  line   }   class  LineItem  {          int  quantity          Item  item   }   class  Item  {          String  name   }   o?.line?.item?.name ! def  o  =  new  Order(          line:  new  LineItem(                  quantity:  2,                  item:  null))   ! println  o.line.item.name !60
  • 172. Null handling class  Order  {          LineItem  line   }   class  LineItem  {          int  quantity          Item  item   }   class  Item  {          String  name   }   o?.line?.item?.name ! def  o  =  new  Order(          line:  new  LineItem(                  quantity:  2,                  item:  null))   ! println  o.line.item.name !60 Safe navigation: will just return null; No NPE
  • 175. The Truth, the Groovy Truth! And what if I could customize the truth?
  • 176. The Groovy Truth assert  !(  null  )   assert  !(    ""    )   assert  !(    []    )   assert  !(      0    ) assert  new  Object()   assert  "string"   assert  [1,  2,  3]   assert  1234 !62
  • 177. The Groovy Truth null, empty, 0-sized, zero are coerced to false assert  !(  null  )   assert  !(    ""    )   assert  !(    []    )   assert  !(      0    ) assert  new  Object()   assert  "string"   assert  [1,  2,  3]   assert  1234 !62
  • 178. The Groovy Truth null, empty, 0-sized, zero are coerced to false assert  !(  null  )   assert  !(    ""    )   assert  !(    []    )   assert  !(      0    ) assert  new  Object()   assert  "string"   assert  [1,  2,  3]   assert  1234 !62 true otherwise
  • 179. Customizing the truth! class  Account  {          String  name          boolean  disabled  =  false   !        boolean  asBoolean()  {  !disabled  }   }   ! assert    new  Account(name:  'current')   assert  !new  Account(name:  'old',  disabled:  true) !63
  • 180. Customizing the truth! class  Account  {          String  name          boolean  disabled  =  false   !        boolean  asBoolean()  {  !disabled  }   }   ! assert    new  Account(name:  'current')   assert  !new  Account(name:  'old',  disabled:  true) while (account), if (account), etc… !63
  • 181. ?:
  • 184. Towards Elvis... def  (x,  y)  =  ['MacBook  Pro',  'unknown'] !65
  • 185. Towards Elvis... def  (x,  y)  =  ['MacBook  Pro',  'unknown'] !65
  • 186. Towards Elvis... def  (x,  y)  =  ['MacBook  Pro',  'unknown'] if  (x  !=  null  &&  x.size()  >  0)  x  else  y !65
  • 187. Towards Elvis... def  (x,  y)  =  ['MacBook  Pro',  'unknown'] if  (x  !=  null  &&  x.size()  >  0)  x  else  y if  (x  &&  x.size())  x  else  y !65
  • 188. Towards Elvis... def  (x,  y)  =  ['MacBook  Pro',  'unknown'] if  (x  !=  null  &&  x.size()  >  0)  x  else  y if  (x  &&  x.size())  x  else  y if  (x)  x  else  y !65
  • 189. Towards Elvis... def  (x,  y)  =  ['MacBook  Pro',  'unknown'] if  (x  !=  null  &&  x.size()  >  0)  x  else  y if  (x  &&  x.size())  x  else  y if  (x)  x  else  y x  ?  x  :  y !65
  • 190. Towards Elvis... def  (x,  y)  =  ['MacBook  Pro',  'unknown'] if  (x  !=  null  &&  x.size()  >  0)  x  else  y if  (x  &&  x.size())  x  else  y if  (x)  x  else  y x  ?  x  :  y x  ?:  y !65
  • 191. Towards Elvis... def  (x,  y)  =  ['MacBook  Pro',  'unknown'] if  (x  !=  null  &&  x.size()  >  0)  x  else  y if  (x  &&  x.size())  x  else  y if  (x)  x  else  y x  ?  x  :  y x  ?:  y Null, empty, zerosized... false, otherwise true! !65
  • 192. Towards Elvis... def  (x,  y)  =  ['MacBook  Pro',  'unknown'] if  (x  !=  null  &&  x.size()  >  0)  x  else  y if  (x  &&  x.size())  x  else  y if  (x)  x  else  y x  ?  x  :  y x  ?:  y Good old ternary operator !65 Null, empty, zerosized... false, otherwise true!
  • 193. Towards Elvis... def  (x,  y)  =  ['MacBook  Pro',  'unknown'] if  (x  !=  null  &&  x.size()  >  0)  x  else  y if  (x  &&  x.size())  x  else  y if  (x)  x  else  y x  ?  x  :  y x  ?:  y Elvis! !65 Good old ternary operator Null, empty, zerosized... false, otherwise true!
  • 194. AST transformations • Abstract Syntax Tree – in memory representation of your program
 before being compiled into bytecode ! • AST transformation == process of transforming the AST of a program before it’s compiled ! • Macro-like compiler hook! !66
  • 195. Lots of AST transformations... • Code generation – @ToString, @EqualsAndHashCode, @Canonical, @TupleConstructor, @InheritConstructors, @Category, @IndexedProperty, @Lazy, @Newify • Class design – @Delegate, @Immutable, @Memoized, 
 @Singleton, @Mixin • Logging – @Log, @Log4j, @Log4j2, @Slf4j !67
  • 196. Lots of AST transformations... • Safer scripting – @ConditionalInterrupt, @ThreadInterrupt, @TimedInterupt • Compiler directives – @Field, @PackageScope, @AnnotationCollector, @DelegatesTo, @TypeChecked, @CompileStatic, @CompileDynamic • Swing patterns – @Bindable, @ListenerList, @Vetoable !68
  • 197. Lots of AST transformations... • Dependencies handling – @Grab, @GrabConfig, @GrabExclude, @GrabResolver • Test assistance – @NotYetImplemented, @ASTTest !69
  • 198. Immutability • Implement immutability 
 by the book ! – final class – tuple-style constructor – private final backing fields – defensive copying of collections – equals() and hashCode() methods – toString() method – ... !70
  • 199. Immutability • Implement immutability 
 by the book ! – final class Can be error-prone to – tuple-style constructor write immutable – private final backing fields classes oneself! – defensive copying of collections – equals() and hashCode() methods – toString() method – ... !70
  • 200. Immutability • A Person class with – a String name – an int age public final class Person {! private final String name;! private final int age;! ! ! ! ! ! ! }! !71 public Person(String name, int age) {! this.name = name;! this.age = age;! }! public String getName() {! return name;! }! public int getAge() {! return age;! }! public int hashCode() {! return age + 31 * name.hashCode();! }! public boolean equals(Object other) {! if (other == null) {! return false;! }! if (this == other) {! return true;! }! if (Person.class != other.getClass()) {! return false;! }! Person otherPerson = (Person)other;! if (!name.equals(otherPerson.getName()) {! return false;! }! if (age != otherPerson.getAge()) {! return false;! }! return true;! }! public String toString() {! return "Person(" + name + ", " + age + ")";! }!
  • 201. Immutability • A Person class with – a String name – an int age public final class Person {! private final String name;! private final int age;! ! ! ! ! ! ! }! !71 Damn verbose Java! public Person(String name, int age) {! this.name = name;! this.age = age;! }! public String getName() {! return name;! }! public int getAge() {! return age;! }! public int hashCode() {! return age + 31 * name.hashCode();! }! public boolean equals(Object other) {! if (other == null) {! return false;! }! if (this == other) {! return true;! }! if (Person.class != other.getClass()) {! return false;! }! Person otherPerson = (Person)other;! if (!name.equals(otherPerson.getName()) {! return false;! }! if (age != otherPerson.getAge()) {! return false;! }! return true;! }! public String toString() {! return "Person(" + name + ", " + age + ")";! }!
  • 202. Immutability • A Person class with – a String name – an int age Damn verbose Java! public final class Person {! private final String name;! private final int age;! ! ! ! ! ! public Person(String name, int age) {! this.name = name;! this.age = age;! }! public String getName() {! return name;! }! public int getAge() {! return age;! }! public int hashCode() {! return age + 31 * name.hashCode();! }! public boolean equals(Object other) {! if (other == null) {! return false;! }! if (this == other) {! return true;! }! if (Person.class != other.getClass()) {! return false;! }! Person otherPerson = (Person)other;! if (!name.equals(otherPerson.getName()) {! return false;! }! if (age != otherPerson.getAge()) {! return false;! }! return true;! }! Although it’s also a valid Groovy program! ! }! !71 public String toString() {! return "Person(" + name + ", " + age + ")";! }!
  • 203. @Immutable import  groovy.transform.*   ! @Immutable   class  Person  {          String  name          int  age   } !72
  • 204. Memoization • Cache the result of previous invocations of closures or methods with the same set 
 of argument values import  groovy.transform.*   ! @Memoized   long  fib(long  n)  {          if  (n  ==  0)  0          else  if  (n  ==  1)  1          else  fib(n  -­‐  1)  +  fib(n  -­‐  2)   }   ! println  fib(40) !73
  • 205. Memoization • Cache the result of previous invocations of closures or methods with the same set 
 of argument values import  groovy.transform.*   Best applied to side-effect free functions ! @Memoized   long  fib(long  n)  {          if  (n  ==  0)  0          else  if  (n  ==  1)  1          else  fib(n  -­‐  1)  +  fib(n  -­‐  2)   }   ! println  fib(40) !73
  • 208. Groovy allows you to be lazy The compiler will do the job for you
  • 209. Groovy allows you to be lazy More concise, more readable code The compiler will do the job for you
  • 210. Groovy allows you to be lazy More concise, more readable code The compiler will do the job for you Less stuff to maintain and worry about
  • 211. @TypeChecked & @CompileStatic • Static type checking with @TypeChecked, throws compilation errors on... – typos in method and variable names – incompatible return types – wrong type assignments ! • Supports fine-grained type inference – « Least Upper Bound » – « Flow typing » !75
  • 212. @TypeChecked & @CompileStatic • Static type checking with @TypeChecked, throws compilation errors on... – typos in method and variable names – incompatible return types You can even extend the – wrong type assignments static type checker! ! • Supports fine-grained type inference – « Least Upper Bound » – « Flow typing » !75
  • 213. @TypeChecked & @CompileStatic • Static type checking with @TypeChecked, throws compilation errors on... – typos in method and variable names – incompatible return types You can even extend the – wrong type assignments ! static type checker! • Supports fine-grained type inference – « Least Upper Bound » – « Flow typing » Type check DSLs or dynamic features! !75
  • 214. @TypeChecked & @CompileStatic ! • What is type checked can also be compiled statically with @CompileStatic ! – generate the same bytecode as javac ! – same performance as Java !76
  • 215. Pi (π) Fibonacci quadrature Java 191 ms 97 ms 3.6 s 2.x Static
 compilation 197 ms 101 ms 4.3 s 1.8 !77 Binary
 trees Primitive optimizations 360 ms 111 ms 23.7 s 1.7 Static compilation performance No prim.
 optimizations 2590 ms 3220 ms 50.0 s
  • 222. M V G
  • 224. GVM
  • 226. GVM: Groovy enVironment Manager • The new kid on the block – http://gvmtool.net/ — @gvmtool ! • Manage parallel versions 
 of the various ecosystem projects ! • Supports... – Groovy, Grails, Griffon, Gradle,Vert.x, Spring Boot ! • On Linux, MacOS, Cygwin, Solaris, FreeBSD !86
  • 229. I’m Spock... ...the Spock testing framework
  • 230. I’m Spock... ...the Spock testing framework
  • 231. Spock example @Grab('org.spockframework:spock-­‐core:0.7-­‐groovy-­‐2.0')   import  spock.lang.*   ! class  MathSpec  extends  Specification  {          def  "maximum  of  two  numbers"()  {              expect:                  Math.max(a,  b)  ==  c   !            where:                  a  |  b  ||  c                  1  |  3  ||  3                  7  |  4  ||  4                  0  |  0  ||  0          }   } !88
  • 232. Spock example @Grab a dependency @Grab('org.spockframework:spock-­‐core:0.7-­‐groovy-­‐2.0')   import  spock.lang.*   ! class  MathSpec  extends  Specification  {          def  "maximum  of  two  numbers"()  {              expect:                  Math.max(a,  b)  ==  c   !            where:                  a  |  b  ||  c                  1  |  3  ||  3                  7  |  4  ||  4                  0  |  0  ||  0          }   } !88
  • 233. Spock example @Grab a dependency @Grab('org.spockframework:spock-­‐core:0.7-­‐groovy-­‐2.0')   import  spock.lang.*   ! class  MathSpec  extends  Specification  {          def  "maximum  of  two  numbers"()  {              expect:                  Math.max(a,  b)  ==  c   !            where:                  a  |  b  ||  c                  1  |  3  ||  3                  7  |  4  ||  4                  0  |  0  ||  0          }   } !88 Meaningful test method names
  • 234. Spock example @Grab a dependency @Grab('org.spockframework:spock-­‐core:0.7-­‐groovy-­‐2.0')   import  spock.lang.*   ! Meaningful test method names class  MathSpec  extends  Specification  {          def  "maximum  of  two  numbers"()  {              expect:                  Math.max(a,  b)  ==  c   Clever use of labels !            where:                  a  |  b  ||  c                  1  |  3  ||  3                  7  |  4  ||  4                  0  |  0  ||  0          }   } !88 for BDD style
  • 235. Spock example @Grab a dependency @Grab('org.spockframework:spock-­‐core:0.7-­‐groovy-­‐2.0')   import  spock.lang.*   ! Meaningful test method names class  MathSpec  extends  Specification  {          def  "maximum  of  two  numbers"()  {              expect:                  Math.max(a,  b)  ==  c   Clever use of labels !            where:                  a  |  b  ||  c                  1  |  3  ||  3                  7  |  4  ||  4                  0  |  0  ||  0          }   } !88 for BDD style Expression to be asserted
  • 236. Spock example @Grab a dependency @Grab('org.spockframework:spock-­‐core:0.7-­‐groovy-­‐2.0')   import  spock.lang.*   Meaningful test method names ! class  MathSpec  extends  Specification  {          def  "maximum  of  two  numbers"()  {              expect:                  Math.max(a,  b)  ==  c   Clever use of labels for BDD style !            where:                  a  |  b  ||  c                  1  |  3  ||  3                  7  |  4  ||  4                  0  |  0  ||  0          }   } !88 Cute datadriven tests! Expression to be asserted
  • 238. @GrabResolver("https://oss.jfrog.org/artifactory/repo")   @Grab("org.ratpack-­‐framework:ratpack-­‐groovy:0.9.0-­‐SNAPSHOT")   import  static  org.ratpackframework.groovy.RatpackScript.ratpack   import  static  org.ratpackframework.groovy.Template.groovyTemplate   ! ratpack  {          handlers  {                  get  {                          response.send  "Welcome!"                  }   !                get("date")  {                          render  groovyTemplate("date.html")                  }   !                assets  "public"          }   }
  • 239. @GrabResolver("https://oss.jfrog.org/artifactory/repo")   @Grab("org.ratpack-­‐framework:ratpack-­‐groovy:0.9.0-­‐SNAPSHOT")   import  static  org.ratpackframework.groovy.RatpackScript.ratpack   import  static  org.ratpackframework.groovy.Template.groovyTemplate   ! ratpack  {          handlers  {                  get  {                          response.send  "Welcome!"                  }   Lightweight Netty-based web app toolkit !                get("date")  {                          render  groovyTemplate("date.html")                  }   !                assets  "public"          }   }
  • 240. Geb • Browser automation solution ! • WebDriver + jQuery selectors + Groovy ! • Handy for – scripting, scraping, automation... – functional / web / acceptance testing • when integrated with JUnit, TestNG or Spock !90
  • 241. Geb — Example import  geb.Browser   ! Browser.drive  {          go  "http://myapp.com/login"   !        assert  $("h1").text()  ==  "Please  Login"   !        $("form.login").with  {                  username  =  "admin"                  password  =  "password"                  login().click()          }   !        assert  $("h1").text()  ==  
                "Admin  Section"   }   !91
  • 242. Geb — Example Drive the browser to this site import  geb.Browser   ! Browser.drive  {          go  "http://myapp.com/login"   !        assert  $("h1").text()  ==  "Please  Login"   !        $("form.login").with  {                  username  =  "admin"                  password  =  "password"                  login().click()          }   !        assert  $("h1").text()  ==  
                "Admin  Section"   }   !91
  • 243. Geb — Example Drive the browser to this site import  geb.Browser   ! Browser.drive  {          go  "http://myapp.com/login"   Check the content of the title !        assert  $("h1").text()  ==  "Please  Login"   !        $("form.login").with  {                  username  =  "admin"                  password  =  "password"                  login().click()          }   !        assert  $("h1").text()  ==  
                "Admin  Section"   }   !91
  • 244. Geb — Example Drive the browser to this site import  geb.Browser   ! Browser.drive  {          go  "http://myapp.com/login"   Check the content of the title !        assert  $("h1").text()  ==  "Please  Login"   !        $("form.login").with  {                  username  =  "admin"                  password  =  "password"                  login().click()          }   !        assert  $("h1").text()  ==  
                "Admin  Section"   }   !91 Find & fill in the form
  • 245. Geb — Example Drive the browser to this site import  geb.Browser   ! Browser.drive  {          go  "http://myapp.com/login"   Check the content of the title !        assert  $("h1").text()  ==  "Please  Login"   !        $("form.login").with  {                  username  =  "admin"                  password  =  "password"                  login().click()          }   !        assert  $("h1").text()  ==  
                "Admin  Section"   }   !91 Find & fill in the form Submit the form
  • 246. Geb — Example Drive the browser to this site import  geb.Browser   ! Browser.drive  {          go  "http://myapp.com/login"   Check the content of the title !        assert  $("h1").text()  ==  "Please  Login"   !        $("form.login").with  {                  username  =  "admin"                  password  =  "password"                  login().click()          }   !        assert  $("h1").text()  ==  
                "Admin  Section"   }   Find & fill in the form Submit the form In the admin section, yeah! !91
  • 247. Geb — With page objects and Spock import  geb.spock.GebSpec   ! class  GoogleWikipediaSpec  extends  GebSpec  {   !        def  "first  result  for  wikipedia  search  should  be  wikipedia"()  {                  given:                  to  GoogleHomePage   !                expect:                  at  GoogleHomePage   !                when:                  search.field.value("wikipedia")   !                then:                  waitFor  {  at  GoogleResultsPage  }   !                and:                  firstResultLink.text()  ==  "Wikipedia"   !                when:                  firstResultLink.click()   !                then:                  waitFor  {  at  WikipediaPage  }          }   } !92
  • 248. Geb — With page objects and Spock import  geb.spock.GebSpec   ! With page objects        def  "first  result  for  wikipedia  search  should  be  wikipedia"()  {   class  GoogleWikipediaSpec  extends  GebSpec  {   !                given:                  to  GoogleHomePage   !                expect:                  at  GoogleHomePage   !                when:                  search.field.value("wikipedia")   !                then:                  waitFor  {  at  GoogleResultsPage  }   !                and:                  firstResultLink.text()  ==  "Wikipedia"   !                when:                  firstResultLink.click()   !                then:                  waitFor  {  at  WikipediaPage  }          }   } !92
  • 249. Geb — With page objects and Spock import  geb.spock.GebSpec   ! With page objects        def  "first  result  for  wikipedia  search  should  be  wikipedia"()  {   class  GoogleWikipediaSpec  extends  GebSpec  {   !                given:                  to  GoogleHomePage   !                expect:                  at  GoogleHomePage   BDD style: given/when/then !                when:                  search.field.value("wikipedia")   !                then:                  waitFor  {  at  GoogleResultsPage  }   !                and:                  firstResultLink.text()  ==  "Wikipedia"   !                when:                  firstResultLink.click()   !                then:                  waitFor  {  at  WikipediaPage  }          }   } !92
  • 250. Geb — With page objects and Spock import  geb.spock.GebSpec   ! With page objects        def  "first  result  for  wikipedia  search  should  be  wikipedia"()  {   class  GoogleWikipediaSpec  extends  GebSpec  {   !                given:                  to  GoogleHomePage   !                expect:                  at  GoogleHomePage   BDD style: given/when/then !                when:                  search.field.value("wikipedia")   ! Wait for slow loading pages                then:                  waitFor  {  at  GoogleResultsPage  }   !                and:                  firstResultLink.text()  ==  "Wikipedia"   !                when:                  firstResultLink.click()   !                then:                  waitFor  {  at  WikipediaPage  }          }   } !92
  • 252. Java’s best friend • Java derived syntax –Flat learning curve –Easy to learn • But goes beyond Java –Concise, expressive, readable –Fit for Domain-Specific Languages • Seamless & transparent Java integration –Mix & match Groovy & Java classes (joint compil.) –No language barrier to cross !94
  • 253. Groovy’s nature ! • Object oriented dynamic language... ! • But... – as type safe as you want it — static type checking – as fast as you need it — static compilation – as functional as you make it — closures... !95
  • 254. Groovy use cases • Scripting tasks, build automation • Extension points for customizing/configuring apps • Business languages & Domain-Specific Languages • Full blown apps – for desktop with Griffon – for the web with Grails, Ratpack, Gaelyk – for web reactive programming with Reactor !96