Appendix     B

Introduction to Groovy

Groovy is an agile and dynamic language for the Java Virtual Machine that builds upon the strengths of Java but has additional powerful features inspired by languages such as Python, Ruby, and Smalltalk. It seamlessly integrates with all existing Java classes and libraries and compiles to Java bytecode so you can use it anywhere you can use Java. Groovy provides the ability to statically type check and statically compile your code for robustness and performance and supports domain-specific languages and other compact syntax so your code becomes easy to read and maintain.

Groovy makes modern programming features available to Java developers with almost zero learning curve; increases developer productivity by reducing scaffolding code when developing web, GUI, database, or console applications; and simplifies testing by supporting unit testing and mocking out of the box.

Getting Started

Let’s start with a traditional “Hello World” program. But first you need to install Groovy. Groovy comes bundled as a .zip file or platform-specific installer for Windows, Ubuntu, and Debian (as well as openSUSE until recent versions). This section explains how to install the zipped version, since it covers the most platforms.

To install Groovy, follow these steps:

  1. Download the most recent stable Groovy binary release .zip file from http://groovy.codehaus.org/Download.
  2. Uncompress groovy-binary-X.X.X.zip to your chosen location.
  3. Set a GROOVY_HOME environment variable to the directory in which you uncompressed the .zip file.
  4. Add the %GROOVY_HOME%in directory to your system path.

Note  Groovy requires Java, so you need to have a version available (while Groovy 1.6 supported JDK 1.4 or greater, for Groovy 1.7 onward, at a minimum JDK 1.5 is needed).

To validate your installation, open a console and type the following:

>groovy -v

You should see something like this:

Groovy Version: 2.0.0 JVM: 1.6.0_31 Vendor: Sun Microsystems Inc. OS: Windows 7

Now you can write your first “Hello World” program (see Listing B-1).

Listing B-1. “Hello World” in Java

1.   public class HelloWorld {
2.      public static void main( String[] args )
3.   System.out.println("Hello World!");
4.      }
5.   }
  • Lines 1 to 2: The default visibility of methods and fields is public, so you can drop the public modifier.
  • Line 2: Groovy supports dynamic typing, so you can drop type information and the return type void on the main().
  • Line 3: Every Groovy object has at its disposure println, which can be seen as a shortcut for System.out.println.
  • Line 3: The semicolon at the end of line is optional, so you can drop that too.

In light of these rules, you can transform Listing B-1 to Listing B-2.

Listing B-2. Transforming “Hello World” Applying Groovy Rules

1.   class HelloWorld {
2.      static main( args ){
3.   println "Hello World!"
4.      }
5.   }

As you can see, Listing B-2 is much more compact. You can write and execute Groovy code in the form of scripts that are also compiled to bytecode. So, you can write the Groovy code illustrated in Listing B-3 for the “Hello World” program.

Note  Any Java class/object is also a Groovy class/object.

Listing B-3. Groovy Script for “Hello World”

println "Hello World!"

You can run Groovy scripts and classes through the command line, GroovyShell, or GroovyConsole.

GroovyShell

GroovyShell is an interactive command-line application (shell) that allows you to create, run, save, and load Groovy scripts and classes. To start GroovyShell, run groovysh. Figure B-1 illustrates using GroovyShell to execute a simple script.

9781430259831_AppB-01.jpg

Figure B-1. Using GroovyShell

As you can see, the script prints vishal. Then you see ===> null. As a matter of convention, Groovy always returns the results of methods. In this case, there is no result, so null is returned. GroovyShell contains a built-in help facility that you can use to learn more about the shell. To access it, type help at the prompt. Figure B-2 shows the help listing.

9781430259831_AppB-02.jpg

Figure B-2. Using GroovyShell help

GroovyConsole

GroovyConsole, shown in Figure B-3, is a graphical version of GroovyShell. It is written using SwingBuilder, a Groovy module that makes building a Swing user interface easier.

9781430259831_AppB-03.jpg

Figure B-3. GroovyConsole

Figure B-4 shows GroovyConsole with the output detached. You can start GroovyConsole in a number of ways, depending on your environment and how you installed Groovy. The easiest way is to execute GroovyConsole, which is located in the Groovy bin directory.

9781430259831_AppB-04.jpg

Figure B-4. Using GroovyConsole with the output detached

The console provides the ability to create, save, load, and execute classes and scripts. Some of the nice features of the console are undo/redo and the ability to inspect variables. If you have to choose between using GroovyShell and GroovyConsole, I recommend GroovyConsole.You can also define classes in scripts and use them right away, as illustrated in Listing B-4.

Listing B-4. Defining a Class in the Script

class HelloWorld {
   def hello( name ){
      "Hello ${name}!"
   }
}
def hw = new HelloWorld()
println hw.hello("Vishal")
  • The return type of the method hello is not of a specific type, so you use the reserved keyword def.
  • The string "Hello" is not a simple java.lang.String. It is, in fact, one of the Groovy features: a GString. These types of strings allow string interpolation, as explained in the next section.

Groovy supports two kinds of strings: regular Java strings and GStrings. A string in Groovy is an instance ofjava.lang.String if it is surrounded by single quotes or if it is surrounded by double or triple quotes with no unescaped dollar sign ($).

GStrings

GStringsare an instance of groovy.lang.GString and allow placeholders to be included in the text. GStrings are not a subclass of String because the String class is final and can’t be extended. A GString is just like a normal string, but it allows the embedding of variables within it using ${..}. The curly braces are required only if the embedded variable is a placeholder for an expression. Groovy supports a concept found in many other languages such as Perl and Ruby called string interpolation, which is the ability to substitute an expression or variable within a string. If you have experience with Unix shell scripts, Ruby, or Perl, this should look familiar. Java doesn’t support string interpolation. You must manually concatenate the values. Listing B-5 is an example of the type of code you need to write in Java, and Listing B-6 shows the same code using a GString.

Listing B-5. Building Strings with Java

String name = "Vishal" ;
String helloName = "Hello " + name ;
System.out.println(helloName) ;

Listing B-6. String Interpolation in Groovy/GString

1.   str1= "Vishal"
2.   str2 = "Hello "
3.   println "$str2$str1"

In line 3, curly braces are not used because curly braces are required only if the embedded variable is a placeholder for an expression. When Groovy sees a string defined with double quotes or slashes and an embedded expression, Groovy constructs an org.codehaus.groovy.runtime.GStringImpl instead of a java.lang.String. When the GString is accessed, the expression is evaluated. Notice that you can include any valid Groovy expression inside the ${} notation; this includes method calls or variable names.

Groovy supports single-line strings and the strings that span multiple lines. In the sections that follow, you will learn a variety of strings supported in Groovy.

Single-Line Strings

Single-line strings can be single quoted or double quoted. A string enclosed in single quotes is taken literally. Strings defined with single quotes do not interpret the embedded expressions, as illustrated in Listing B-7.

Listing B-7. Single-Quote Strings Do Not Interpret Embedded Expressions

name = "vishal"
s1 = 'hello $name'
println s1
Here is the output:
hello $name

You can nest a double quote in a single quote, as illustrated in Listing B-8.

Listing B-8. Nested Double Quote in Single Quote

s1 = 'hello "vishal"'
println s1

Strings defined using double quotes will interpret embedded expressions within the string, as illustrated in Listing B-9.

Listing B-9. Double-Quoted Strings Interpret Embedded Expressions

def name = "vishal"
s1 = "hello $name"
println s1
Here is the output:
hello vishal

You can nest single quotes in double quotes, as illustrated in Listing B-10.

Listing B-10. Nested Single Quote in Double Quote

s1 = "hello 'vishal'"
println s1
Here is the output:
hello 'vishal'

Multiline Strings

Groovy supports strings that span multiple lines. A multiline string is defined by using three double quotes or three single quotes. Multiline string support is useful for creating templates or embedded documents (such as XML templates, SQL statements, HTML, and so on). For example, you could use a multiline string and string interpolation to build the body of an e-mail message, as shown in Listing B-11. String interpolation with multiline strings works in the same way as it does with regular strings: multiline strings created with double quotes evaluate expressions, and single-quoted strings don’t.

Listing B-11. Using Multiline Strings

def name = "Vishal"
def multiLineString = """
Hello, ${name}
This is a multiline string with double quotes
"""
println multiLineString
Hello, Vishal
This is a multiline string with double quotes

Slashy Strings

As mentioned earlier, slashes can be used to define strings. The slashy notation has a nice benefit: additional backslashes are not needed to escape special characters. The only exception is escaping a backslash: /. The slashy notation can be helpful when creating a regular expression requiring a backslash or a path. Listing B-12 illustrates the difference between using regular quotes and slashes to define a regular expression to match a file system path.

Listing B-12. Using Slashy Strings

def quotedString = 'Hello Vishal'
def slashyString = /Hello Vishal/
println slashyString
Hello Vishal

Listing B-12 defines two variables and assigns them to a directory path. The first variable definition, quotedString, uses the single-quote notation to define a string. Using the single-quote notation requires that the embedded backslash be escaped using an additional backslash.

Multiline Slashy Strings

Slashy strings can also span multiple lines. This is particularly useful for multiline regexes when using the regex freespacing comment style (see Listing B-13).

Listing B-13. Using Multiline Slashy Strings

1.    def name = "vishal"
2.    def path= "c:/groovy"
3.    def multilineSlashy = /
4.    Hello $name
5.    path= $path
6.    dollar = $
7.    path = c:/groovy
8.    /
9.    println multilineSlashy
Hello vishal
path= c:/groovy
dollar = $
path = c:/groovy

Let’s take a look at Listing B-13 in a little more detail.

  • Line 1 defines a variable, name, and assigns the value "vishal" to it.
  • Line 2 defines a variable, path, and assigns the value "c:/groovy" to it.
  • Line 3 defines a variable, multilineSlashy, and assigns a multiline string to it that includes up to line 8, between the slashes.
  • Line 4 has an expression, $name, that is evaluated to vishal, as shown in the output.
  • Line 5 has an expression, $path, that is evaluated to c:/groovy, as shown in the output.
  • Line 6 has a $ sign, but it is not an expression, so it is displayed in the output.
  • Line 7 has a slash, which needs to be escaped.

Dollar Slashy Strings

In multiline slashy strings, a slash still needs to be escaped. Moreover, in multiline slashy strings, an unescaped dollar sign that is not an expression results in a MissingPropertyException, as illustrated in Listing B-14.

Listing B-14. MissingPropertyException in Multiline Slashy String

1.    def name = "vishal"
2.    def path= "c:/groovy"
3.    def multilineSlashy = /
4.    Hello $name
5.    path= $path
6.    dollar = $test
7.    path = c:/groovy
8.     /
9.    println multilineSlashy
Caught: groovy.lang.MissingPropertyException: No such property: test for class:
hello
groovy.lang.MissingPropertyException: No such property: test for class: hello
at hello.run(hello.groovy:3)

In Listing B-14, there is no such property as test; $test in line 6 is interpreted as an expression, which results in a MissingPropertyException.

Now, let’s look at the code in Listing B-15, specifically line 6.

Listing B-15. Unescaped Dollar Sign in Multiline Slashy String

1.    def name = "vishal"
2.    def path= "c:/groovy"
3.    def multilineSlashy = /
4.    Hello $name
5.    path= $path
6.    dollar = $ test
7.    path = c:/groovy
8.     /
9.    println multilineSlashy

This time Groovy does not interpret $ test in line 6 as an expression because there is an empty space between $ and test, and it renders the output as follows:

Hello vishal
path= c:/groovy
dollar = $ test
path = c:/groovy

With a dollar slashy string, you are no longer required to escape the slash with a preceding backslash (multiline slashy strings require the slash to be escaped), and you can use $$ to escape a $ or use $/ to escape a slash if needed, as illustrated in Listing B-16.

Listing B-16. Using Dollar Slashy String

1.    def name = "vishal"
2.    def path= "c:/groovy"
3.    def dollarSlashy = $/
4.    Hello $name
5.    path = $path
6.    dollar = $$test
7.    path = c:/groovy
8.    /$
9.    println dollarSlashy
Hello vishal
path= c:/groovy
dollar = $test
path = c:/groovy

Let’s take a look at Listing B-16 in more detail.

  • Line 3 defines a dollarSlashy string that includes up to line 8.
  • Line 6 has a $test, which has caused a MissingPropertyException in the case of the multiline slashy string in Listing B-14, which you now escape using a $.

Collective Datatypes

Groovy supports a number of different collections, including arrays, lists, maps, ranges, and sets. Let’s look at how to create and use each of the collection types.

Arrays

A Groovy array is a sequence of objects, just like a Java array (see Listing B-17).

Listing B-17. Creating and Using Arrays

1.    def stringArray = new String[3]
2.    stringArray[0] = "A"
3.    stringArray[1] = "B"
4.    stringArray[2] = "C"
5.    println stringArray
6.    println stringArray[0]
7.    stringArray.each { println it}
8.     println stringArray[-1..-3]
  • Line 1 creates a string array of size 3.
  • Lines 2 to 4 use an index to access the array.
  • Line 7 illustrates using the each() method to iterate through the array. The each() method is used to iterate through and apply the closure on every element.
  • Line 8 shows something interesting—it uses a range, which will be discussed shortly, to access the array.
[A, B, C]
A
A
B
C
[C, B, A]

Lists

A Groovy list is an ordered collection of objects, just as in Java. It is an implementation of the java.util.List interface. Listing B-18 illustrates how to create a list and common usages.

Listing B-18. Creating and Using Lists

1.    def emptyList = []
2.    def list = ["A"]
3.    list.add "B"
4.    list.add "C"
5.    list.each { println it }
6.    println list[0]
7.    list.set(0, "Vishal")
8.    println list.get(0)
9.     list.remove 2
10.    list.each { println it }
  • On line 1, an empty list is created by assigning a property the value of [].
  • Lines 2 to 4 create a list with an item already in it and add items to the list.
  • Line 5 iterates over the list, invoking the closure to print out the contents. The each() method provides the ability to iterate over all elements in the list, invoking the closure on each element.
  • Lines 6 illustrates how to use an index to access a list. Lists are zero-based.
  • Line 7 shows how to use an index to assign position 0 the value "Vishal".
  • Line 8 accesses the list using the get() method.
A
B
C
A
Vishal
Vishal
B

Maps

A Groovy map is an unordered collection of key-value pairs, where the key is unique, just as in Java. It is an implementation of java.util.Map. Listing B-19 illustrates how to create maps and common usages.

Listing B-19. Creating and Using Maps

1.    def map = ['a':'Value A', 'b':'Value B ']
2.    println map["a"]
3.    println map."a"
4.    println map.a
5.    println map.getAt("b")
6.    println map.get("b")
7.    println map.get("c", "unknown")
8.    println map
9.    map.d = "Value D"
10.    println map.d
11.    map.put('e', 'Value E')
12.    println map.e
13.    map.putAt 'f', 'Value F'
14.    println map.f
15.    map.each { println "Key: ${it.key}, Value: ${it.value}" }
16.    map.values().each { println it }
  • Line 1 illustrates how to define a map with multiple entries. When using the square bracket notation, the colon separates the key from the value.
  • Lines 2 to 10 show several different techniques for accessing the map.
  • Lines 11 to 13 show several different techniques for putting items into the map.
Value A

Value A

Value A

Value B

Value B

unknown

[a:Value A, b:Value B , c:unknown]

Value D

Value E

Value F

Key: a, Value: Value A

Key: b, Value: Value B

Key: c, Value: unknown

Key: d, Value: Value D

Key: e, Value: Value E

Key: f, Value: Value F

Value A

Value B

unknown

Value D

Value E

Value F

Ranges

A range is a list of sequential values. Logically, you can think of it as 1 through 10 or as a through z. As a matter of fact, the declaration of a range is exactly that: 1..10 or 'a'.'z'. A range is a list of any objects that implement java.lang.Comparable. The objects have next() and previous() methods to facilitate navigating through the range. Listing B-20 illustrates some of the things you can do with ranges.

Listing B-20. Creating and Using Ranges

1.    def numRange = 0..9
2.    numRange.each {print it}
3.    println ""
4.    println numRange.contains(5)
5.    def reverseRange = 9..0
6.    reverseRange.each {print it}
7.    def exclusiveRange = 1..<10
8.    println ""
9.    exclusiveRange.each {print it}
10.    def alphabet = 'a'..'z'
11.    println ""
12.    println alphabet.size()
13.    println alphabet[25]
  • Lines 1, 5, 7, and 10 illustrate how to define ranges.
  • Line 1 defines an inclusive range of numbers.
  • Line 10 defines an inclusive range of lowercase letters.
  • Line 7 defines an exclusive list of numbers. The range results in a range of numbers 1 to 9, excluding 10.
  • Line 5 creates a range in reverse order, 9 through 0. Frequently, ranges are used for iterating. In Listing B-20, each() was used to iterate over the range. Listing B-21 shows three ways you can use a range to iterate: one in Java and two in Groovy.
0123456789

true

9876543210

123456789

26

z

Listing B-21. Iterating with Ranges

for (i in 0..9) {
println i
}
(0..9).each { i->
println i
}

The each() method is used to iterate through and apply the closure on every element.

Sets

A Groovy set is an unordered collection of objects, with no duplicates, just as in Java. It is an implementation of java.util.Set. By default, unless you specify otherwise, a Groovy set is a java.util.HashSet. If you need a set other than a HashSet, you can create any type of set by instantiating it, as in def TreeSet = new TreeSet(). Listing B-22 illustrates how to create sets and common usages.

Listing B-22. Creating and Using Sets

def  set = ["A", "B" ] as Set
set.add "C"
println set
set.each { println it }
set.remove "B"
set.each { println it }
[A, B, C]

A

B

C

A

C

Creating an empty set is similar to creating an empty list. The difference is the addition of the Set clause. One of the important differences between a list and a set is that a list provides indexed-based access and a set doesn’t.

Methods

Listing B-23 illustrates defining a method in Groovy the Java way, and Listing B-24 shows the same thing but using the Groovy syntax instead.

Listing B-23. Defining a Method the Java Way

public String hello(String name) {
return "Hello, " + name;
}

Listing B-24. Defining a Method Using the Groovy Idiom

def hello(name) {
"Hello, ${name}"
}
  • The return type and the return statement are not included in the body of the method. Groovy always returns the results of the last expression—in this case, the GString "Hello, . . .".
  • The access modifier public is not defined. Unless you specify otherwise, Groovy defaults all classes, properties, and methods to public access.

Closures

Functional programming gives you the right foundation to think about concurrency on the basis of underlying principles: referential transparency, higher-order functions, and immutable values. Understanding these key elements is crucial to understanding closures (and other functional features recently introduced in Groovy). Functional programming is built on the premise of pure functions. In mathematics, functions are pure in that they lack side effects. Consider the classic function sin(x): y = sin(x). No matter how many times sin(x) is called, no global or contextual state is modified internally by sin(x). Such a function is pure, free of side effects, and oblivious to the context. This obliviousness to the surrounding context is known as referential transparency. If no global state is modified, concurrent invocation of the function is steadfast. In functional programming, functions are first-class citizens, meaning functions can be assigned to variables, functions can be passed to other functions, and functions can be returned as values from other functions. And such functions, which take functions as arguments or return a function, are called higher-order functions.

Referential transparency, higher-order functions, and immutable values together make functional programming a better way to write concurrent software. Though functional languages are all about eliminating side effects, a language that never allowed for side effects would be useless. As a matter of fact, introducing side effects is crucial to any language. All functional languages have to provide mechanisms for introducing side effects in a controlled manner because even though functional languages are about pure programming, a language that does not sanction side effects would be useless because input and output are essentially the ramification of side effects.

Understanding Closures

One of the techniques to introduce side effects in a controlled manner is a closure. A closure definition in Groovy follows this syntax:

{ [closure parameters ->] closure body}

where [closure parameters->] is an optional comma-delimited list of arguments, and the closure body can be an expression as well as zero or more Groovy statements. The arguments look similar to a method’s parameter list, and these arguments may be typed or untyped. A Groovy closure is a block of reusable code within curly braces, {}, which can be assigned to a property or a variable or passed as a parameter to a method. A closure is executed only when it is called, not when it is defined. Listing B-25 illustrates this.

Listing B-25. Calling a Closure

1.    def closureVar = {println 'Hello world'}
2.    println "closure is not called yet"
3.    println " "
4.    closureVar.call()
  • Line 1: This line has the closure with no parameters and consists of a single println statement. Because there are no parameters, the parameter List and the -> separator are omitted. The closure is referenced by the identifier closureVar.
  • Line 4: This line uses the explicit mechanism via the call() method to invoke the closure. You may also use the implicit nameless invocation approach: closureVar(). As shown in the output, the closure prints “Hello world” when it is called in line 4, not when it is defined in line 1.

Here is the output:

closure is not called yet
Hello world

Listing B-26 illustrates the same closure as in Listing B-25 but with the parameter.

Listing B-26. Closure with Parameter

1.    def closureVar = {param -> println "Hello ${param}"}
2.    closureVar.call('world')
3.    closureVar ('implicit world')
  • Line 2: This is an explicit call with the actual argument 'world'.
  • Line 3: This is an implicit call with the actual argument 'implicit world'.
Hello world
Hello implicit world

As Listing B-27 illustrates, the formal parameters to a closure may be assigned default values.

Listing B-27. Parameters with Default Values

1.    def sayHello= {str1, str2= " default world" -> println "${str1} ${str2}" }
2.    sayHello("Hello", "world")
3.    sayHello("Hello")
  • Line 1: The sayHello closure takes two parameters, of which one parameter, str2, has a default value.
  • Line 3: Only one actual parameter is provided to the closure, and the default value of the second parameter is used.

Here is the output:

Hello world
Hello default world

Closures always have a return value. The value may be specified via one or more explicit return statements in the closure body, as illustrated in Listing B-28, or as the value of the last executed statement if return is not explicitly specified, as illustrated in Listing B-29.

Listing B-28. Using Return Keyword

def sum = {list -> return list.sum()}
assert sum([2,2]) == 4

Listing B-29. Return Keyword Optional

def sum = {list -> list.sum()}
assert sum([2,2]) == 4

To understand closures, you have to understand the concept of free variables. A closure is formed when the body of a function refers to one or more free variables. Free variables are variables that are not local to the function and are not passed as arguments to the function but are defined in the enclosing scope where the function is defined. Thus, closures refer to variables not listed in their parameter list (free variables). They are “bound” to variables within the scope where they are defined. Listing B-30 illustrates this.

Listing B-30. Free Variables

def myConst = 5
def incByConst = { num -> num + myConst }
assert  incByConst(10) == 15

The runtime “closes over” the free variable (myConst in Listing B-30) so that it is available when the function is executed. That is, the compiler creates a closure that envelops the external context of free variables and binds them.

Implicit Variables

Within a Groovy closure, an implicit variable (it) is defined that has a special meaning. If only one argument is passed to the closure, the arguments list and the -> symbol can be omitted, and the closure will have access to it, which represents that one argument, illustrated in Listing B-31.

Listing B-31. Using it

def closure = {println "Hello ${it}"}
closure.call('world')
Hello world

A closure always has at least one argument, which will be available within the body of the closure via the implicit parameter it if no explicit parameters are defined. The developer never has to declare the it variable—like the this parameter within objects, it is implicitly available. If a closure is invoked with zero arguments, then it will be null.

Explicit Declaration of Closure

All closures defined in Groovy are essentially derived from the type Closure. Because groovy.lang is automatically imported, you can refer to Closure as a type within your code. This is an explicit declaration of a closure. The advantage of declaring a closure explicitly is that a nonclosure cannot be inadvertently assigned to such a variable. Listing B-32 illustrates how to declare a closure explicitly.

Listing B-32. Explicit Declaration of a Closure

Closure closure = { println it }

Reusing the Method as a Closure

Groovy provides the method closure operator (.&) for reusing the method as a closure. The method closure operator allows the method to be accessed and passed around like a closure. Listing B-33 illustrates this.

Listing B-33. Reusing the Method as a Closure

1.    def list = ["A","B","C","D"]
2.    String printElement(String element) {
3.    println element
4.    }
5.    list.each(this.&printElement)

Listing B-33 creates a list of names and iterates through the list to print out the names. In line 5, the method closure operator (.&) causes the method printElement to be accessed as a closure. Here is the output:

A

B

C

D

Passing a Closure as a Parameter

A closure is an object. You can pass closures around just like any other objects. A common example is iterating over a collection using a closure (see Listing B-34).

Listing B-34. Passing a Closure As a Parameter

def list = ["A", "B", "C"]
def x = { println it }
list.each(x)
A

B

C

Specialized Operators

Groovy includes several standard operators found in other programming languages, as well as operators that are specific to Groovy that make it so powerful. In the sections that follow, you will learn the specialized operators in Groovy such as spread, Elvis, safe navigation, field, method closure, and diamond operators.

Spread Operator

The spread operator (*.) is a shorthand technique for invoking a method or closure on a collection of objects. Listing B-35 illustrates the usage of the spread operator for iterating over a list.

Listing B-35. Using the Spread Operator

1.    def map = [1:"A", 2:"B", 3:"C", 4:"D"]
2.    def keys = [1, 2, 3, 4]
3.    def values = ["A", "B", "C", "D"]
4.    assert map*.key == keys
5.    assert map*.value == values

Line 4 and line 5 use the spread operator to access keys and values of the map.

Elvis Operator

The Elvis operator (?:)is a shorthand version of the Java ternary operator. For example, b= a ?: 1 could be interpreted as follows:

if(a != 0)
b = a
else
b = 1

Listing B-36 illustrates using the Java ternary and Elvis operators in Groovy.

Listing B-36. Using the Elvis Operator

def firstName = author.firstName == null ? "unknown" : author.firstName // Java ternary
def firstName2 = author.firstName ?: "unknown" // Groovy Elvis

In both cases, if author.firstName is null, then firstName is set to unknown. The author.firstName fragment of the Elvis operator example is known as the expression. If the expression evaluates to false or null, then the value after the colon is returned.

Safe Navigation/Dereference Operator

The safe navigation/dereference operator (?.) is used to avoid null pointer exceptions. Consider the situation where you have an Author object and you want to print the firstName. If the Author object is null when you access the firstName property, you will get a NullPointerException (see Listing B-37).

Listing B-37. Using the Safe Navigation/Dereference Operator

class Author {
String firstName
String lastName
def printFullName = {
println "${firstName} ${lastName}"
}
}
Author author
println author.firstName

The code in Listing B-37 throws a NullPointerException. In Java, you add a null check this way:

if (author != null) {
println "Author FirstName = ${author.firstName}"
}

Listing B-38 illustrates how to add the null check using the safe navigation/dereference operator in Groovy.

Listing B-38. Using the Safe Navigation/Dereference Operator

class Author {
String firstName
String lastName
def printFullName = {
println "${firstName} ${lastName}"
}
}
Author author
println "Author FirstName = ${author?.firstName}"

Field Operator

Groovy provides a way to bypass the getter and access the underlying field directly. Bypassing the getter and accessing the underlying field is not recommended, however, because it is a violation of encapsulation. Listing B-39 shows an example of using the field operator (.@).

Listing B-39. Using the Field Operator

class Author {
String name
}
def author = new Author(name: "Vishal")
println author.name
printlnauthor.@name
Vishal

Vishal

In this example, the first println uses the getter to access name, and the second println bypasses the getter to access name directly.

Method Closure Operator

The method closure operator (.&)allows the method to be accessed and passed around like a closure (see Listing B-40).

Listing B-40. Using the Method Closure Operator

def list = ["A","B","C"]
list.each { println it }
String printName(String name) {
println name
}
list.each(this.&printName)
A

B

C

A

B

C

This example creates a list of names and iterates through the list to print out the names. A printName() method is created that prints the name parameter. Lastly and the main point of this example, the list is iterated, executing the printName() method as a closure. Using the method closure operator, you are able to expose Java methods as closures.

Diamond Operator

The diamond operator (<>)is introduced in Groovy to avoid the repetition of parameterized types. The parameterized types can be omitted and replaced with pointy brackets, which look like a diamond. Listing B-41 shows a usual verbose way of defining a list.

Listing B-41. A Simple Groovy Script: Hello.groovy

List<List<String>> list1 = new ArrayList<List<String>>()

Listing B-42 illustrates how to use the diamond operator.

Listing B-42. Using the Diamond Operator

List<List<String>> list1 = new ArrayList<>()

Summary

This appendix introduced the basics of Groovy. One appendix is not enough to learn any language or technology, but that said, the introduction to Groovy in this appendix is substantial enough to write web applications using Grails. In this appendix, you first learned how to install Groovy; then it showed how to write a “Hello World” program with Groovy. Then you learned how to run Groovy scripts and classes and looked at various strings supported in Groovy. Then the chapter briefly introduced the collective datatypes of Groovy, and you learned what a closure is and how to use it in Groovy. Lastly, you learned how to use specialized operators available in Groovy.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.186.79