As promised in the previous entry I am continuing series of Groovy posts. Starting from simple introduction we are moving to intermediate and advanced topics in the future posts.
What is Groovy’s origin?
Everything started in 2003 when James Strachan (official Groovy creator) wrote to Bob McWhirter:
Wouldn’t it be “groovy” if we could have native syntax for lists, maps and regexs in Java like in most scripting languages?
Wouldn’t it by “groovy” if we could have duck typing in Java?
Wouldn’t it be “groovy” if we had closures and properties in Java?
Certainly it would be “groovy” as a result of what we have brilliant scripting language on the JVM.
Groovy is a dynamic language for Java Virtual Machine. It is compiled directly to byte code which is then executed on the JVM alongside Java byte code. It is one of the main strengths of the language because it uses the same API, I mean JDK, collections, etc. as Java, has the same security and threading models and finally the same object oriented concepts.
Joint-compilation
Talking about Groovy’s complementary to Java nature joint-compilation term must be mentioned.
Have a look at the following diagram:
Java vs Groovy
public class HelloWorld{ private String name; public void setName(String name){ this.name = name; } public String getName(){ return name; } public String greet(){ return "Hello " + name; } public static void main(String[] args){ HelloWorld helloWorld = new HelloWorld(); helloWorld.setName("Groovy"); System.out.println(helloWorld.greet()); } }
public class HelloWorld{ private String name; public void setName(String name){ this.name = name; } public String getName(){ return name; } public String greet(){ return "Hello " + name; } public static void main(String[] args){ HelloWorld helloWorld = new HelloWorld(); helloWorld.setName("Groovy"); System.out.println(helloWorld.greet()); } }
class HelloWorld{ String name String greet(){ "Hello $name" } } def helloWorld = new HelloWorld(name: "Groovy") println helloWorld.greet()
- everything is public if not stated differently
- automatic getters and setters
- semicolons at the end of the line are optional
- variable interpolation using GStrings
- return statement is optional; function returns value returned by the last statement
- dynamic typing using def keyword
Groovy tries to be as natural as possible for Java developers, however there are some differences which should be mentioned and remembered:
- floating point number literals are BigDecimal type by default
- Groovy uses default imports which means that the following packages are imported by default:
- java.io.*
- java.lang.*
- java.math.BigDecimal
- java.math.BigInteger
- java.net.*
- java.util.*
- groovy.lang.*
- groovy.util.*
- operator == means equals for all types; if you need to check identity use method is() like object.is(anotherObject)
- operator in is a keyword
- array in Java can be declared as follows int[] arr = {1,2,3,4}; but in Groovy we need
int[] arr = [1,2,3,4]
Native syntax for data structures
- lists
- def list = [1,’a’]
- maps
- def map = [PL:’Poland’, UK:’United Kingdom’] – keys are strings by default
- ranges
- def range = 10..15
- assert range.size() == 6
- assert range.get(1) == 11
- assert range instanceof java.util.List
Operators
Except operators which are common with Java, Groovy supports a list of additional operators:
- spread operator (*.)
- used to invoke action on all items of a given aggregate object
- object*.action which is equivalent to object.coolect{ child->child?.action }
- assert [‘a’, ‘bb’]*.size() == [1, 2]
- Java field (.@)
- Groovy automatically creates getters for all properties in a class
- operator allows getting property value directly, without using getter method
- object.@fieldName
- Elvis operator (?:)
- shorter version of Java’s ternary operator
- ternary operator:
- def phoneNumber= user.phoneNumber ? user.phoneNumber : “N/A”
- Elvis operator:
- def phoneNumber = user.phoneNumber ?: “N/A”
- safe navigation operator
- used to avoid NullPointerException
- def phoneNumber = user?.phoneNumber
- if user is null, variable phoneNumber will get null value instead of throwing NullPointerException
Closures
Closures, one of the “grooviest” features in my opinion. It can be defined as reusable piece of code which can be passed around as it was a string or an integer.
{ println "Hello World!" }
Closures like functions, can get arguments and return values.
{ name -> println "Hello $name" } { number -> number * number }
Moreover they can be assigned to variables.
def closure = { a,b -> a + b }
Closures can access variables which are in particular closure scope, which is quite obvious. However variables defined within the scope which closure is defined in can be accessed as well.
def CONST = 1 def incrementByConstance = { value -> value + CONST } println incrementByConstance(5)
Some more closure examples:
square = { it * it } //it - value passed to the closure [1,2,3,4].collect(square)
printMap = { key, value -> println "key=" + key + " value=" + value } ["PL" : "Poland", "UK" : "United Kingdom"].each(printMap)
Stay tuned for further posts regarding Groovy.