4. Groovy Programming Language
Dynamic JVM language
Static typing and static compilation capabilities
Familiar and easy to learn syntax for Java
developers
Concise, readable and expressive
Smooth Java integration
Interoperates with Java and any third-party Java libraries
6. Groovy distribution
Download from Bintray
https://bintray.com/groovy/
SDKMAN! (The Software Development Kit Manager)
OSX, Linux, Cygwin
Posh-GVM (POwerSHell Groovy enVironment Manager)
Windows
7. The Groovy Development Kit
A number of helper methods added to the JDK
Working with IO
Working with collections
Working with threads
Handy utilities
...
14. Type inference
def message = 'Groovy is awesome!'
assert message.toUpperCase() == 'GROOVY IS AWESOME!'
assert message.upper() == 'GROOVY IS AWESOME!' // Compile-time error
15. Flow typing
def value = 'Groovy is awesome'
value = value.toUpperCase()
assert value == 'GROOVY IS AWESOME'
value = 9d
value = Math.sqrt(value)
assert value == 3.0
value = value.toLowerCase(value) // Compile-time error
16. Static compilation
class User {
String name
int age
}
@groovy.transform.CompileStatic
def test() {
def user = new User(name: 'John Smith', age: 30)
int age = user.age // getAge() possible runtime error: GroovyCastException
}
User.metaClass.getAge = { -> "30" } // runtime modification
test()
19. Syntax
The majority of Java syntax is valid Groovy
Primitive types
Packages and imports
Control flow statements
◇ More flexible switch
◇ For-in loop
Exception handling
◇ No distinction between checked and unchecked exceptions
Classes and object instantiation
28. Lambdas
Runnable run =
() -> System.out.println("Run");
Java Groovy
Runnable run = { println 'Run' }
29. Runtime dispatch (multimethods)
String whoIsAwesome(String arg) {
return "Groovy is awesome!";
}
String whoIsAwesome(Object arg) {
return "Java is awesome!";
}
Object o = "Object";
String result = whoIsAwesome(o);
assertEquals("Java is awesome", result);
Java
assertEquals("Groovy is awesome",
result);
Groovy
30. Other differences with Java
Interfaces do not support default implementation (Java 8)
Automatic resource management blocks not supported (Java 7)
No difference between checked and uncheck exceptions
Assertion in Groovy is always enabled
power asserts
48. Spaceship operator (<=>)
assert (1 <=> 1) == 0
assert (1 <=> 100) == -1
assert (100 <=> 1) == 1
assert ('a' <=> 'z') == -1
assert ('Groovy is awesome' <=> 'Java is not so bad') == -1
49. Spread operator (*.)
class User {
String name
int age
}
def users = [
new User(name: 'John', age: 33),
new User(name: 'George', age: 35),
null]
assert users*.name == ['John', 'George', null]
50. Spreading method arguments
int add(int a, int b, int c, int d) {
a + b + c + d
}
def args = [1, 2, 7, 10]
assert add(*args) == 20
args = [1, 2, 7]
assert add(*args, 10) == 20
53. List to type coercion
class User {
String name
int age
User(String name, int age) {
this.name = name
this.age = age
}
}
def user1 = ['John', 30] as User
User user2 = ['John', 30]
54. Map to type coercion
def map
map = [
i: 10,
hasNext: { map.i > 0 },
next: { map.i-- },
]
def iter = map as Iterator
assert iter.collect { it } == [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
56. Constructors (positional arguments)
// Constructor invocation with new keyword
def user1 = new User('John', 30)
// Using coercion with as keyword
def user2 = ['John', 30] as User
// Using coercion in assignment
User user3 = ['John', 30]
57. Constructors (named arguments)
def user1 = new User()
def user2 = new User(name: 'John')
def user3 = new User(age: 30)
def user4 = new User(name: 'John', age: 30)
59. Named arguments
def createUser(Map args) { new User(args.name, args['age']) }
def user = createUser(name: 'John', age: 30)
assert user.name == 'John'
assert user.age == 30
60. Default arguments
def createUser(String name, int age = 30) { new User(name, age)
}
def user = createUser('John')
assert user.name == 'John'
assert user.age == 30
61. Properties
class User {
final String name = 'Jesus'
int age
}
class User {
private final String name = 'Jesus'
private int age
String getName() { return name }
void setAge(int age) { this.age = age }
int getAge() { return age }
}
63. Direct field access
class User {
public String name
String getName() {
"User's name is $name"
}
}
def user = new User(name: 'John')
assert user.name == "User's name is John"
class User {
public String name
String getName() {
"User's name is $name"
}
}
def user = new User(name: 'John')
assert user.@name == 'John'
66. Closure examples
{ 1 + 5 }
{ -> 1 + 5 }
{ println it }
{ num -> println num }
{ int x, int y = 10 -> "Sum of $x and $y is ${x + y}"}
67. def closure = { Writer w ->
w.writeLine 'Groovy creates a new BufferedWriter for the file and passes it to the closure.'
w.writeLine 'It also ensures the stream is flushed and closed after the closure returns.'
w.writeLine 'Even if an exception is thrown in the closure.'
}
assert closure instanceof Closure
def file = new File('sample.txt')
file.withWriter(closure)
Closure is an object
72. � this
The enclosing class of a closure definition
� owner
The enclosing object of a closure definition (a class or a closure)
� delegate
An object where methods calls or properties are resolved if no
receiver
of the message is defined
Delegation
73. Example
class User {
def name
}
def user = new User(name: 'John')
def getUserName = { "The name is $name" }
assert getUserName() == 'The name is John' // MissingPropertyException
getUserName.delegate = user
assert getUserName() == 'The name is John'
75. Closures
First class citizens of type groovy.lang.Closure
Can access any variables of the surrounding context
Support delegation concept
Method reference via GroovyClass.&groovyMethod
Lambda expressions
Instances of SAM type they represent
Can access only effectively final variables of the surrounding context
Method reference via JavaClass::javaMethod
Closures vs Java 8 lambda expressions
79. Runtime metaprogramming
POJO
Regular Java object
Class written in Java or other JVM language
POGO
Class written in Groovy
Extends java.lang.Object and implements groovy.lang.GroovyObject
GroovyInterceptable
All methods intercepted through invokeMethod
83. methodMissing
class User {
def methodMissing(String name, def args) {
if (name.startsWith("findBy")) {
def field = name[6].toLowerCase() + name[7..-1]
return "Looking for a user by $field=${args.first()}"
} else
throw new MissingMethodException(name, this.class, args)
}
}
def user = new User()
assert user.findByFirstName('John') == 'Looking for a user by firstName=John'
assert user.findByAge(30) == 'Looking for a user by age=30'
84. Example
def writer = new StringWriter()
def xml = new MarkupBuilder(writer)
xml.movies() {
movie(year: 1977) {
name('Star Wars: Episode IV')
director('George Lucas')
}
movie(year: 1989) {
name('Indiana Jines and the Last Crusade')
director('Steven Spielberg')
}
}
85. Example (cont’d)
<movies>
<movie year='1977'>
<name>Star Wars: Episode IV</name>
<director>George Lucas</director>
</movie>
<movie year='1989'>
<name>Indiana Jines and the Last Crusade</name>
<director>Steven Spielberg</director>
</movie>
</movies>
86. MetaClass
Defines the behaviour of any Groovy or Java class
Client API defined via MetaObjectProtocol
Contract with Groovy runtime system
Cached in MetaClassRegistry
Available via metaClass property
88. Adding/changing methods
class User {
String name
}
User.metaClass.nameInUpperCase = { -> name.toUpperCase() }
User.metaClass.nameInLowerCase << { -> name.toLowerCase() } // Has to be a new method
def user = new User(name: 'John Smith')
assert user.nameInUpperCase() == 'JOHN SMITH'
assert user.nameInLowerCase() == 'john smith'
89. Adding/changing constructors
class User {
String name
}
User.metaClass.constructor << { String name -> new User(name: name) }
def user = new User('John Smith')
assert user.name == 'John Smith'
90. Adding/changing properties
class User {
String name
}
User.metaClass.age = 30
def user = new User(name: 'John Smith')
assert user.age == 30
user.age = 35
assert user.age == 35
91. Adding/changing static methods
class User {
String name
}
User.metaClass.static.newInstance << { name -> new User(name: name) }
def user = User.newInstance('John Smith')
assert user.name == 'John Smith'
92. Compile-time metaprogramming
Allows code generation at compile-time
Alters Abstract Syntax Tree (AST) of a program
The changes are visible in bytecode
Callable from other JVM languages
Usually better performance
93. AST transformations
Global AST transformation
Applied as soons as they are found on compile classpath
No out-of-the-box transformations available
Local AST transformation
Applied by annotating the source code with markers
Supports parameters
103. “
It is about how fast you can understand
the code.
104. What does this code do?
def process(def arg1, def arg2, def arg3) {
[arg1, arg2, arg3].inject('') { x, y ->
if (y <= 0) return "${x}00"
if (y > 255) return "${x}ff"
def s = ''
for (int n = y; n > 0; n = n.intdiv(16)) {
int r = n % 16
s = r < 10 ? r + s : "${(char) (((int) 'A') - 10 + r)}$s"
}
s.length() == 1 ? "${x}0$s" : "$x$s"
}
}
105. And now?
String rgbToHex(int r, int g, int b) {
[r, g, b].inject('') { acc, val ->
if (val <= 0) return "${acc}00"
if (val > 255) return "${acc}ff"
def hex = ''
for (int i = val; i > 0; i = i.intdiv(16)) {
int j = i % 16
hex = j < 10 ? j + hex : "${(char) (((int) 'A') - 10 + j)}$hex"
}
hex.length() == 1 ? "${acc}0$hex" : "$acc$hex"
}
}
106. Best practices
Use explicit types for public APIs
Interfaces
Document client contract
Use descriptive names (for everything)
Avoid using the same variable name for different things
Use optional elements explicitly if it helps code readability
parentheses, return keyword
107. Best practices (cont’d)
Restrict access to members that are not part of API
private, protected, @PackageScope
Use @TypeChecked or @CompileStatic capabilities if possible
Keep your code segments small and isolated
Especially if making use of duck typing
Cover code with as many test suites as reasonable
Refactoring
108. “
Groovy is not a replacement for Java, it
is addition to Java.
111. Thanks!
Any questions?
You can find me at petr.giecek.82@gmail.com
https://www.linkedin.com/in/petrgiecek
https://github.com/pgiecek
112. Credits
Special thanks to all the people who made and
released these awesome resources for free:
Presentation template by SlidesCarnival
Photographs by Unsplash