Sunday, 27 January 2019

Groovy: Working with Closures


Closures are one of the important features of Groovy. Closure is a piece of code that is written in-between {}.

How to define a closure?
Syntax
Closure closureName = {arguments -> body}

Example
Closure welcomeMe = {name -> "Hello Mr.$name, A very good Evening"}

HelloWorld.groovy
Closure welcomeMe = {name -> "Hello Mr.$name, A very good Evening"}

def message = welcomeMe("Krishna")

println (message)

Output
Hello Mr.Krishna, A very good Evening

You can pass closure arguments of other APIS. For example, list each method takes a closure as an argument and call the closure on every element of it.


HelloWorld.groovy
Closure welcomeMe = {name -> println "Hello Mr.$name, A very good Evening"}

names = ["Krishna", "Ram", "Saurav", "Sachin"]

names.each(welcomeMe)

Output
Hello Mr.Krishna, A very good Evening
Hello Mr.Ram, A very good Evening
Hello Mr.Saurav, A very good Evening
Hello Mr.Sachin, A very good Evening

Groovy is very flexible in writing compact code, for example, you can rewrite the code like below.
names = ["Krishna", "Ram", "Saurav", "Sachin"].each({name -> println "Hello Mr.$name, A very good Evening"})

You can ignore parenthesis () while passing the closure.
names = ["Krishna", "Ram", "Saurav", "Sachin"].each {name -> println "Hello Mr.$name, A very good Evening"}

‘it’ argument
If the closure takes only a single parameter, Groovy provides a default name ‘it’, so that you don’t need to declare it explicitly.

You can rewrite the above snippet like below.
names = ["Krishna", "Ram", "Saurav", "Sachin"].each {println "Hello Mr.$it, A very good Evening"}

Referring to existing methods as closures
You can refer existing methods as closures using method reference (.&) operator.

For example, below statement creates a closure using the method welcomeUser of UserUtil class.
UserUtil userUtil  = new UserUtil()
Closure welcome = userUtil.&welcomeUser

Find the below working application.


HelloWorld.groovy
class UserUtil{
 
 void welcomeUser(String name){
  println "Hello Mr.$name, A very good Evening"
 }
}

UserUtil userUtil  = new UserUtil()
Closure welcome = userUtil.&welcomeUser

names = ["Krishna", "Ram", "Saurav", "Sachin"]
names.each(welcome)

Output
Hello Mr.Krishna, A very good Evening
Hello Mr.Ram, A very good Evening
Hello Mr.Saurav, A very good Evening
Hello Mr.Sachin, A very good Evening

Below example uses existing method to filter the countries.


HelloWorld.groovy
class CountryUtil{
 
 boolean isValidToWork(String country){
  return ["India", "Sri lanka", "Australia"].contains(country)
 }
}

CountryUtil countryUtil  = new CountryUtil()

Closure filterCountries = countryUtil.&isValidToWork

countries = ["America", "Japan", "India", "Germany", "Australia"]
validCountries = countries.findAll(filterCountries)

println (validCountries)

Output
[India, Australia]

Overloading vs closures
You can create a closure to overloaded method. Depends on the number of argument passed to the closure corresponding closure will get called at run time.


HelloWorld.groovy
class Arithmetic{
 int sum(int a, int b){
  return a + b
 }
 
 String sum(String a, String b){
  return a + b
 }

}

Arithmetic arithmetic = new Arithmetic()
Closure add = arithmetic.&sum

def result1 = add(10, 20)
def result2 = add("Hello", "World")

println "result1 : $result1"
println "result2 : $result2"

Output
result1 : 30
result2 : HelloWorld

Specify default values to closure arguments
You can specify the default values to closure parameters.


HelloWorld.groovy
Closure add = {a = 1, b = 2 -> a + b}

result1 = add()
result2 = add(10)
result3 = add(10, 20)

println "result1 : $result1"
println "result2 : $result2"
println "result3 : $result3"

Output
result1 : 3
result2 : 12
result3 : 30

add()
In this case, I am not passed any arguments to the closure add, so the argument ‘a’ is assigned with default value 1 and ‘b’ is assigned with default value 2.

add(10)
In this case, I passed one  arguments to the closure add, so the argument ‘a’ is assigned with value 10 and ‘b’ is assigned with default value 2.

Note
a.   A closure is an object internally

b.   Method closures are limited to instance methods.




Previous                                                 Next                                                 Home

No comments:

Post a Comment