Objective

By the end of this blog you will be able understand and work with below topics:

  1. Groovy Script Syntax Basics
  2. Working with Collections
  3. Functions and Closures in Groovy Script

Table of Contents

  1. Objective
  2. Table of Contents
  3. Groovy Script Syntax Basics
    1. Variables and data types
    2. Strings and GString interpolation
    3. Basic operators and control structures
      1. Basic Operators
      2. Control Structures
  4. Working with Collections
    1. Working with List and Arrays
    2. Working with Maps
    3. String as Collection
    4. Iterating Collections with Loops
    5. Groovy’s Powerful Collection Manipulation Capabilities
  5. Functions and Closures in Groovy Script
    1. Functions and Closures in Groovy Script
    2. Defining and Using Functions
    3. Introduction to Closures: Defining and Using
    4. Closure Scope, Parameters, and Return Values
    5. Power of Closures
  6. Whats next?

Groovy Script Syntax Basics

Variables and data types

Declaring an object, field or variable name:

//only for string, but format is same
def stringVariable = 'StringValue' 

In this blog we will deal with below 7 types of data types. Note for most data types Groovy self infers the data type of declared variable based on the value assigned to it, hence the ‘def’ keyword. If you assign value as ‘3’ it will take it as String, if you assign it as 3, it will take it as integer, if you assign it as 3.14, it will take it as float.

//declaring String variable
def stringVariable = 'some string value'
String strVariable = 'Hello World'

//declaring number variables
def numberVariable = 3
double pi = 3.14

//declaring Boolean
boolean booleanVariable = true
def isXYZ = false

//declaring Lists
List myListOne = [1, 'two', 3.0, true]
def myListTwo = [1, 'two', 3.0, true]

//declaring maps
Map myMap = ['name':'John', 'age':30]
def myMap = ['name':'John', 'age':30]

//declaring Arrays
int[] intArray = [1, 2, 3]
def intArray = [1, 2, 3] as int[]

//declaring pattern for regex functionality
def pattern = ~/[a-z]+/

Strings and GString interpolation

There are two types of string objects in Groovy: plain regular strings (String) and Groovy String (GString). The key difference between the two is ability to utilize expressions, and this capability is called ‘String interpolation’ i.e. you can extrapolate the value of a string variable within another string. How? See below.

Regular String

//nothing special here, same as good old java
def helloWorld = 'Hello World'
def helloMars = "Hello Mars"

GString

//first lets declare a regular string variable
def regString = "Regular String"
//Now lets define a GString variable
def v_gString = "I am not a ${regString}"
//above line will print>> I am not a Regular String

Here we used a simple expression in value of variable v_gString to fetch the value of simple string variable regString. This technique is called String interpolation.

Note:

When a GString is passed to a context expecting a java.lang.String, it gets automatically converted to a plain Java String. This conversion happens after all expressions in the GString have been evaluated.

Basic operators and control structures

In Groovy, like in many programming languages, operators and control structures form the backbone of writing logic and flow control. Here’s a concise overview:

Basic Operators

  1. Arithmetic Operators: For basic mathematical operations.
    + (Addition), - (Subtraction), * (Multiplication), / (Division), % (Modulus).
  2. Comparison Operators: To compare values.
    == (Equal to), != (Not equal), > (Greater than), < (Less than), >= (Greater than or equal to), <= (Less than or equal to).
  3. Logical Operators: For boolean logic.
    && (Logical AND), || (Logical OR), ! (Logical NOT).
  4. Assignment Operators: For assigning values to variables.
    = (Simple assignment), +=, -=, *=, /=, %=, etc. (Compound assignment operators).
  5. Elvis Operator (?:): A shorthand for ternary conditional expressions.
    def result = someTest ? valueIfTrue : valueIfFalse
    validate condition defined in “someTest”, if true, returns valueIfTrue else returns valueIfFalse
  6. Safe Navigation Operator (?.): Avoids null pointer exceptions.
    def result = obj?.method() (returns null if obj is null).
  7. Spread Operator (*.): Apply an operation to all items in a collection.
    def lengths = ['Groovy', 'Java'].*.length()
    Above example calculates length of each String Value in the Array.

Control Structures

  1. If-Else Statements: Basic conditional logic.
def age = 25

if (age >= 18) {
  println "Adult"
} else {
  println "Minor"
}

Moreover, as discussed previously, try to build habit of using Elvis Operator rather than if-else block in groovy. The same logic can be written using Elvis operator as:

println (age >= 18) ? “Adult” : “Minor”

  1. Switch Statement: Multi-way branching.
def dayOfWeek = "Tuesday"

switch (dayOfWeek) {
  case "Monday":
    println "Start of the week!"
    break
  case "Tuesday":
  case "Wednesday":
  case "Thursday":
    println "Midweek hustle."
    break
  case "Friday":
    println "TGIF!"
    break
  case "Saturday":
  case "Sunday":
    println "Weekend vibes."
    break
  default:
    println "Invalid day of week."
}

However, if you use Concise Expression Form of Groovy, a simplified form is:

def greeting = switch (dayOfWeek) {
  case "Monday": "Good morning!"
  case "Tuesday", "Wednesday", "Thursday": "Hello!"
  case "Friday": "TGIF!"
  case "Saturday", "Sunday": "Happy weekend!"
  else: "Greetings!"
}
  1. For Loop: Iterating over a range or collection.
  • Traditional: for (int i = 0; i < 5; i++) { /* code */ }
  • Enhanced: for (item in collection) { /* code */ }

While above is similar to good old Java way, even more simplified way of doing this in Groovy is using ‘eachWithIndex’ function.

def colors = ["red", "green", "blue"]
colors.eachWithIndex { value, index ->
  println "$index: $value"
}
  1. While and Do-While Loops: Execute a block while a condition is true. It is same as how it was with Java.
  • while (condition) { /* code */ }
  • do { /* code */ } while (condition)
//While example
def count = 1
while (count <= 5) {
  println "Count: $count"
  count++
}

//do-while example
def input = ""
do {
  print "Enter a word (or 'quit' to exit): "
  input = System.console().readLine()
  println "You entered: $input"
} while (input != "quit")
  1. Try-Catch-Finally: Exception handling.
def number = 0

try {
  println "Enter a number to divide by: "
  def divisor = System.console().readLine() as Integer
  println "100 / $divisor = ${100 / divisor}"
} catch (ArithmeticException e) {
  println "Error: Cannot divide by zero."
} catch (NumberFormatException e) {
  println "Error: Invalid input. Please enter a number."
} finally {
  println "This code always executes, regardless of exceptions."
}
  1. Closures: A special feature in Groovy, closures are anonymous blocks of code that can be passed around and executed.
  • def closure = { /* code */ }

Below is an example of closure. We will go over it wherever applicable.

// Define a closure that calculates the square of a number
def square = { number -> number \* number }

// Use the closure
println square(5)  // Output: 25

Groovy enhances these operators and control structures with its own syntactic sugar, making the code more concise and expressive. For instance, the Elvis operator is useful for dealing with nullable expressions, and closures provide a powerful way to handle functions as first-class citizens. These features, combined with Groovy’s dynamic nature, make it a flexible and efficient language for scripting and general-purpose programming.

Working with Collections

Working with List and Arrays

Below piece of code will acquaint you with basic methods available to be used with Lists and Arrays.

//list and array
def languages = []
languages.add("Hello")
languages << "World"
languages.push("Everyone")
//languages.pop() //pop works in reverse to push
//Below command prints [Hello, World, Everyone]
println(languages)
//Below Command prints [EVERYONE, HELLO, WORLD]
println(languages\*.toUpperCase()) 
//prints new line
println()
//prints String at index 1 >> World
println(languages.get(1))
//prints String at index 2 >> Everyone
println(languages[2])

Working with Maps

Below piece of code will clear up basic methods to be used with maps.

//Working with map
def cars = [:]
//put methods takes key and value
cars.put("white", "sedan")
//below method enters a key 'black' with value 'hatchback'
cars.black = "hatchback"
//below method append a key 'grey' with value 'helicopter' after the last value in the map
cars << ["grey": "helicopter"]
//prints [white:sedan, black:hatchback, grey:helicopter]
println(cars)
//prints 'sedan'
println(cars.get('white'))
//prints 'hatchback'
println(cars['black'])
//prints 'helicopter'
println(cars.grey)

String as Collection

In groovy each string can be seen and worked with, as a ‘collection’:

def hello = "Hello, World"
//substring method picks characters between index 3 and 7
println(hello[3..7]) //prints-> lo, W

Iterating Collections with Loops

Below are a few ways to iterate over a list or array. It might need a bit familiarity with how closures work.

//below code loops over languages array
languages.eachWithIndex{ language, index -> println("${index}. ${language}")}

/\*prints
0. Hello
1. World
2. Everyone
\*/

For maps too it is similar, as can be seen below:

cars.eachWithIndex{ car, i -> println("${i}. ${car}")}

/\*prints
0. white=sedan
1. black=hatchback
2. grey=helicopter
\*/

Groovy’s Powerful Collection Manipulation Capabilities

Groovy’s collection manipulation capabilities are one of its most powerful and useful features, making it particularly well-suited for scripting and data processing tasks. While its not possible to demostrate each function in this blog, below are the points you can take into account to further your coding practices

  • Collection Methods - you can use methods each, collect, find, findAll, groupBy for common tasks
    • Example: myList.each { println it } - prints each element.
  • SQL-like Operations on Collections - Groovy supports SQL-like operations on collections using the findAll, groupBy, sort, collect, and each methods.
    • Example : myList.findAll { it > 2 } - returns elements greater than 2.
  • Spread Operator (*.) - Apply an operation to every item in a collection.
    • Example: def lengths = ['Groovy', 'Java']*.length() - returns a list of lengths of each string.

There are many more but this just gives you an idea, how you have different ways to make your groovy code concise yet readable.

Functions and Closures in Groovy Script

Functions and Closures in Groovy Script

Groovy, a dynamic language for the Java platform, enhances traditional Java functions with additional features and introduces closures, a powerful concept that extends the language’s capabilities. Understanding how functions and closures work in Groovy is crucial for effective scripting and programming.

Defining and Using Functions

Functions in Groovy are defined similarly to methods in Java but with more flexibility. They can be defined with or without specifying the return type or parameter types, thanks to Groovy’s dynamic typing.

def sayHello(name) {
    return "Hello, ${name}!"
}
println sayHello("Alice")

In this example, sayHello is a simple function that takes a name and returns a greeting. The use of def instead of a specific return type is a hallmark of Groovy’s dynamic nature.

Introduction to Closures: Defining and Using

Closures in Groovy are blocks of code that can be passed around and executed. They are similar to lambda expressions in other languages but are more powerful.

def greeting = { name -> "Hello, ${name}!" }
println greeting("Bob")

Here, greeting is a closure that takes a single parameter, name, and returns a greeting string.

Closure Scope, Parameters, and Return Values

Closures in Groovy can access and modify variables in their surrounding scope. They can also accept multiple parameters and have return values.

def outerVariable = 10
def sum = { a, b ->
    outerVariable += a + b
    return outerVariable
}
println sum(5, 5) // Outputs 20

The closure sum modifies the outerVariable and returns the result.

Power of Closures

Closures in Groovy go beyond simple blocks of code, offering features like:

  • Currying: Creating a new closure from an existing one with some arguments pre-filled.
  • Memorization: Caching the results of closures for efficiency.
  • Composition: Combining closures to build more complex logic.
def add = { a, b -> a + b }
def addFive = add.curry(5)
println addFive(10) // Outputs 15

In this example, addFive is a new closure derived from add, pre-filled with one argument.

Note: Full disclosure, you may or or may not get to use closures very frequently in your real world transformation code. However you can focus on loops with closures for your practice. I see that being used comparably more than other patterns.

Whats next?

Hopefully, you have worked with this blog on your IDE and googled some functions, methods, definitions.

Now that we are through with basics and our Groovy ABCs are good, we can proceed with Cloud Integration specific scripting topics like XML and JSON parsing and writing UDFs.

And thats what we will do in next blog!