CHAPTER 2

image

Groovy Basics

Chapter 1 introduced you to Groovy, its relationship to Java, and where the two languages differ. This chapter will delve into the Groovy language. First, you will learn about Groovy scripts, including compiling and running Groovy scripts using the command Line, Groovy Shell, and Groovy Console. Then we will focus on specific aspects of the Groovy language: assertions, strings, regular expressions, collections, ranges, control structures, methods, closures, and operators.

Scripts

You will be using the Groovy language to build domain objects, controllers, and services. But that isn’t the only way to use Groovy. In addition to building classes, you can use Groovy as a scripting language. You will see detailed examples of scripts in subsequent chapters. But here we’ll start with a simple script.

Listing 2-1 is an example of a very simple Groovy “Hello” script that takes an argument and uses it to print a message.

Listing 2-1.  A Simple Groovy Script: Hello.groovy

println "Hello ${args[0]}, may Groovy be with you."

Execute the script by typing the following on the command Line:

>groovy Hello "Luke Skywalker"

The script will output the results:

Hello Luke Skywalker, may Groovy be with you.

On execution of the script, Groovy generates a class with the same name as the script source file, including a main method that contains the script source. The equivalent Java application would look like Listing 2-2.

Listing 2-2.  The Java Version: HelloJava.java

package com.apress.beginninggrails.cli.scripts;
public class HelloJava {
    public static void main(String[] args) {
        System.out.println( "Hello "+ args[0]+", may Java be with you." );
    }
}

Notice how much more verbose the Java version is compared to the Groovy version. With Java, you need to define a class and a main method. You also must fully qualify the println method, add parentheses, and terminate it with a semicolon. Then you need all of the closing curly braces. Even if you are a Java fan, you have to admit that the Groovy example is a good bit shorter and easier to read! Furthermore, you don’t need to go through a separate step of compiling Groovy before it is executed.

Using Script Functions

Like with most scripting languages, you can organize Groovy scripts into blocks of reusable code. In scripts, these blocks are called functions. Listing 2-3 is an example of creating and using a function. It creates a simple function to print a name and calls the function with two different names.

Listing 2-3.  A Script Function:PrintFullName.groovy

def printFullName(firstName, lastName) {
println "${firstName} ${lastName}"
}
printFullName('Luke', 'SkyWalker')
printFullName('Darth', 'Vader')

This example defines the printFullName function, which takes two parameters. Next, the function is invoked twice: once to print Luke Skywalker and again to print Darth Vader.

Compiling Groovy

In the previous examples, we let Groovy compile the script on the fly. Like with Java, you can compile Groovy to Java byte code. Listing 2-4 illustrates compiling the Groovy script from Listing 2-1.

Listing 2-4.  Compiling Groovy with groovyc

groovyc Hello.groovy

As you might expect, compiling Hello. Groovy results in Hello.class. Because Groovy compiles to Java bytecode, you can use the Java command line to execute it.

Listing 2-5.  Running the Groovy Program Using Java

java -cp %GROOVY_HOME%/embeddable/groovy-all-2.0.0.jar;. Hello "Luke Skywalker"

Here is the output:

Hello Luke Skywalker

Being able to run the Groovy program using Java proves it—Groovy is Java. If you look at Listing 2-5, you’ll see that the only thing special required to run the Groovy compilers to include groovy-all-<version>.jar on the classpath.

The Groovy compiler is a joint compiler. It can compile Groovy and Java code at the same time. The joint compiler first became available in Groovy 1.5 through a generous donation by JetBrains, the makers of IntelliJ IDEA. The joint compiler allows you to compile Groovy and Java files with a single compile statement. Listings 2-6 and 2-7 are a Groovy file and a Java file, respectively, to demonstrate joint compilation.

Listing 2-6.  A Sample Groovy File: Name.groovy

class Name
{
String firstName
String toString() { return "Hello ${firstName}, Java calling Groovy" }
}

Listing 2-7.  A Sample Java File:SayHello.java

public class SayHello
{
    public static void main(String args[ ])
    {
        Name name = new Name();
        name.setFirstName( args[0] );
        System.out.println( name.toString() );
    }
}

The Java class, SayHello, instantiates the Groovy class Name and sets the firstName property to a value passed in on the command Line. Listing 2-8 illustrates compiling and executing the programs.

Listing 2-8.  Joint Compile and Execute

groovyc *.groovy *.java
java -cp %GROOVY_HOME%/embeddable/groovy-all-2.0.0.jar;. SayHello "Luke"

Here is the output:

Hello Luke, Java calling Groovy

Compiling the Groovy and Java classes is accomplished by telling groovy to compile files matching the file pattern ending in .groovy and .java. You run the program in the same way that you run any other Java program—just include groovy-all-<version>.jar in the classpath.

Running Groovy

You can run Groovy scripts and classes through the command Line, Groovy Shell, or Groovy Console. Let’s look at each technique.

Command Line

To run Groovy from the command line, you have several options:

  • Use Groovy directly by typing groovy MyPgm at the command line.

    If you are running a script, Groovy will generate a class with a main method containing the script commands, compile the script, and execute it. If you don’t want to recompile the file each time it is run, you can use the third option.

  • Compile the file using groovy into a class and execute it using Java. You saw an example of this approach in the previous section.
  • If you’re in the Windows environment and Groovy was installed with the Windows installer with the PATHEXT option, you can omit the leading groovy and just type MyPgm.groovy. The PATHEXT option associates files ending with .groovy to the Groovy runtime. On Unix platforms, you can use a shebang at the top of the file to get the same result:
    #!/usr/bin/groovy
    println "Hello ${args[0]}, may Groovy be with you."

Groovy Shell

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

9781430248064_Fig02-01.jpg

Figure 2-1.  Using the Groovy Shell

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.

The Groovy Shell 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 2-2 shows the help listing.

9781430248064_Fig02-02.jpg

Figure 2-2.  Groovy Shell help information

Groovy Console

The Groovy Console, shown in Figure 2-3, is a graphical version of the Groovy Shell. It is written using SwingBuilder, a Groovy module that makes building a Swing user interface easier.

9781430248064_Fig02-03.jpg

Figure 2-3.  Groovy Console

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

9781430248064_Fig02-04.jpg

Figure 2-4.  Groovy Console with detached output

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 the Groovy Shell and the Groovy Console, we recommend the Groovy Console.

Assertions

As a developer, if you have used JUnit (or any of the flavors of JUnit), you already have some idea what an assertion is. An assertion is used to validate that an expected condition is true. If the expected condition is not true, a java.lang.AssertionError is thrown. You test that the expected condition is true by using Groovy expressions. Listing 2-9 illustrates the Java and Groovy versions of assert.

Listing 2-9.  Java and Groovy Assertions

// Java assert
assert 1==2 : "One isn't Two";
// Groovy assert
assert 1==2 : "One isn't Two"

As you can see, the Groovy assert syntax is the same as Java’s, except for the ending semicolon. The message is to the right of the expression and separated by a colon. As with Java, the message portion of the assert is optional.

image Tip  As a best practice, when you are using assertions, you should include a message. It will help the next person maintaining your code to understand its intent.

When an assertion fails, Groovy throws a java.lang.AssertionError. Listing 2-10 is the output of the failing Groovy assertion in Listing 2-9.

Listing 2-10.  Assertion Failure

Caught: java.lang.AssertionError: One isn't Two. Expression: <1 == 2>
java.lang.AssertionError: One isn't Two. Expression: <1 == 2>
                  at Hello.run<Hello.groovy:2>
D:groovygroovy-2.0.0>

Power Asserts

Groovy’s assert keyword just checks that the expression passed to it is true or false. If false, it just tells you the expression was false, and gives the value of variables used in the expression, but nothing more. With Power Asserts, the output of the assert provides a visual representation of the value of each sub expression of the expression being asserted, as illustrated in Listing 2-11.

Listing 2-11.  Power Assert Feature

assert new File('HelloWorld.txt') == new File('Hello.txt')

Caught: Assertion failed:

assert new File<'HelloWorld.txt'> == new File<'Hello.txt'>
       ¦                           ¦ ¦
       HelloWorld.txt              ¦ Hello.txt
                                   false
Assertion failed:

assert new File<'HelloWorld.txt'> == new File<'Hello.txt'>
       ¦                           ¦ ¦
       HelloWorld.txt              ¦ Hello.txt
                                   false
         at Hello.run<Hello.groovy:2>

Assertions are very handy and one of the cornerstones of good testing. They also do a great job of clarifying intentions. You will see assertions in many of the examples throughout this book.

Strings

Groovy supports two kinds of strings: regular Java strings and GStrings. A string in Groovy is an instance of java.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

GStrings are 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 only required 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. String interpolation 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 2-12 is an example of the type of code you need to write in Java.

Listing 2-12.  Building Strings with Java

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

Listing 2-13.  String Interpolation in Groovy/GString

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

In Line 3, curly braces are not used because curly braces are only required 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.

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 2-14.

Listing 2-14.  Single Quote String does not Interpret Embedded Expressions

name = "vishal"
s1 = 'hello $name'
println s1

Here is the output:

hello $name

Listing 2-15.  Nested Double Quote in Single Quote

s1 = 'hello "vishal"'
println s1

Here is the output:

hello "vishal"

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

Listing 2-16.  Double Quote Strings Interpret Embedded Expressions

def name = "vishal"
s1 = "hello $name"
println s1

Here is the output:

hello vishal

Listing 2-17.  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 very 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 2-18. 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 2-18.  Using Multiline Strings

def name = "Jim"
def multiLineQuote = """
Hello, ${name}
This is a multiline string with double quotes
"""
println multiLineQuote
println multiLineQuote.class.name
def multiLineSingleQuote = '''
Hello, ${name}
This is a multiline string with single quotes
'''
println multiLineSingleQuote
println multiLineSingleQuote.class.name

Running the code in Listing 2-18 results in the following output:

Hello, Jim
This is a multiline string with double quotes

org.codehaus.groovy.runtime.GStringImpl

Hello, ${name}
This is a multiline string with single quotes

Java.lang.String

Slashy Strings

As mentioned earlier, slashes can be used to define strings. The slashy notation has a very 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 2-19 illustrates the difference between using regular quotes and slashes to define a regular expression to match a file system path.

Listing 2-19.  Using Slashy Strings

def winpathQuoted='C:\windows\system32'
def winpathSlashy=/C:windowssystem32/
println winpathSlashy // C:windowssystem32
assert winpathSlashy ==∼ '\w{1}:\\.+\\.+'
assert winpathSlashy ==∼ /w{1}:\.+\.+/

Listing 2-19 defines two variables and assigns them to a directory path. The first variable definition, winpathQuoted, 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. The first assert statement, which tests the regular expression defined using single quotes, also requires the addition of an extra backslash to escape a backslash.

Notice how using the slashy notation doesn’t require the additional backslashes.

Clearly, it is easier to write and read winpath Slashy, and the second regular expression is easier to write and read as well. Regular expressions and the ==∼ operator will be covered in more detail in the “Regular Expressions” section later in this chapter.

Multiline Slashy Strings

Slashy strings can also span multiple lines. This is particularly useful for multiline regexs when using the regex free-spacing comment style.

Listing 2-20.  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

Here is the output:

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

Let’s take a look at Listing 2-20 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.
  • Line5 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 2-21.

Listing 2-21.  MissingPropertyException in Multiline Slashy String

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

In Listing 2-21, there is no such property as test; $test in Line 7 is interpreted as an expression, which results in a MissingPropertyException.

Now, let us look at the code in the Listing 2-22, specifically Line 7.

Listing 2-22.  Unescaped Dollar Sign in Multiline Slashy String

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

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

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

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

Listing 2-23.  Using Dollar Slashy String

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

Let’s take a look at Listing 2-23 in more detail:

  • Line 4 defines a dollarSlashy string that includes up to Line 9.
  • Line 7 has a $test, which had caused a MissingPropertyException in the case of the multiline slashy string in Listing 2-21, which we now escape using a $.

Regular Expressions

Regular expressions, sometimes referred to regex, are a technique for identifying and manipulating text using a pattern notation. They have been popular in scripting languages such as Unix shell scripting and Perl for a long time, and were added to Java in version 1.4.

image Note  Regular expressions are extremely robust and powerful. This section discusses Groovy’s support of regular expressions. For a full exploration of regular expressions, refer to a book devoted to that subject. You can also find many useful tutorials on the Internet.

A regular expression is a sequence of characters to create a pattern that is applied to a string. The pattern is defined by a pattern language. Table 2-1 shows some of the more common patterns in the Java regular expression language.

Table 2-1. Summary of Regular-Expression Constructs

Construct Matches
Characters
x The character x
\ The backslash character
The tab character (u0009)
The newline (line feed) character (u000A)
The carriage-return character (u000D)
f The form-feed character (u000C)
e The escape character (u001B)
Character Classes
[abc] a, b, or c (simple class)
[^abc] Any character except a, b, or c (negation)
[a-zA-Z] a through z or A through Z, inclusive (range)
[a-d[m-p]] a through d, or m through p: [a-dm-p] (union)
[a-z&&[def]] d, e, or f (intersection)
[a-z&&[^bc]] a through z, except for b and c: [ad-z] (subtraction)
[a-z&&[^m-p]] a through z, and not m through p: [a-lq-z] (subtraction)
Predefined Character Classes
. Any character (may or may not match line terminators)
d A digit: [0–9]
D A nondigit: [^0–9]
s A whitespace character: [ x0Bf ]
S A non-whitespace character: [^s]
w A word character: [a-zA-Z_0-9]
W A nonword character: [^W]
Boundary Matchers
^ The beginning of a line
$ The end of a line
 A word boundary
B A nonword boundary
A The beginning of the input
G The end of the previous match
 The end of the input but for the final terminator, if any
z The end of the input
Greedy Quantifiers
X? X, once or not at all
X* X, zero or more times
X+ X, one or more times
X{ n} X, exactly n times
X{ n,} X, at least n times
X{ n, m} X, at least n but not more than m times
Reluctant Quantifiers
X?? X, once or not at all
X*? X, zero or more times
X+? X, one or more times
X{ n}? X, exactly n times
X{n,}? X, at least n times
X{ n, m}? X, at least n but not more than m times
Possessive Quantifiers
X?+ X, once or not at all
X*+ X, zero or more times
X++ X, one or more times
X{ n}+ X, exactly n times
X{ n,}+ X, at least n times
X{ n, m}+ X, at least n but not more than m times
Logical Operators
XY X followed by Y
X| Y Either X or Y
(X) X, as a capturing group

Groovy Regular Expression Operators

Groovy leverages Java’s regular expression support and makes it easier through Groovy’s

String support. Groovy also adds three convenience operators:

  • The match operator (==∼)
  • The find operator (=∼)
  • The pattern operator (∼string)

Match Operator

The match operator (==∼) returns true if the regular expression exactly matches the subject.

Listing 2-24 shows some examples of using the match operator.

Listing 2-24.  Using the Match Operator

1. assert "abc" ==∼ 'abc'
2. assert "abc" ==∼ /abc/
3. assert "abcabc" ==∼ /abc/ // Fails – not an exact match
4. assert "abc" ==∼ /^a.c/ // Starts with a, 1 char, ends with c
5. assert "abc" ==∼ /^a../ // Starts with a, 2 chars
6. assert "abc" ==∼ /.*c$/ // One or more chars end with c
7. assert "abc" ==∼ ".*c$" // Slashy string is better

Line 3 shows that unless it is an exact match, the match will fail (return false). Lines 4–6 illustrate a couple of ways of defining a regular expression that matches the subject. Line 7 is another example of defining the regular expression on Line6, except it uses double quotes instead of slashes. The important thing to note is that using the double quotes requires the $ to be escaped using a (==∼)backslash.

Find Operator

The find operator (=∼) returns a java.util.regex.Matcher. A matcher is a component that applies a regular expression to a string. The result is a two-dimensional array of matches.

The first dimension contains the match, and the second dimension contains the groups within the match. A group is defined within the regular expression using parentheses. In the example in Listing 2-25, the regular expression defines four groups. When the expression is applied to a string, the groups are individually accessible. This is useful for identifying and accessing portions of a string.

Listing 2-25.  Using the Find Operator

1. def winpath=/C:windowssystem32somedir/
2. def matcher = winpath =∼ /(w{1}):\(w+)\(w+)\(w+)/
3. println matcher
4. println matcher[0] // ["C:windowssystem32somedir", "C", "windows",
5. // "system32", "somedir"]
6. println matcher[0][1] // C
7. def newPath = matcher.replaceFirst('/etc/bin/')
8. println newPath // /etc/bin

Here is the output:

java.util.regex.Matcher[pattern=(w{1}):\(w+)\(w+)\(w+) region=0,27
lastmatch=]
["C:windowssystem32somedir", "C", "windows", "system32", "somedir"]
C
/etc/bin/

Line 1 defines winpath as a directory path string. Line 2 applies a regular expression to the winpath variable using the find operator and returns a java.util.regex.Matcher. The regular expression is set up as a series of group-capturing expressions. Referring to Table 2-1, you can see that w is a word character and the + means one or more. When the regular expression matches the variable, the individual group values are available from the matcher. When Line 3 is invoked, you can see that matcher is in fact a java.util.regex.Matcher and the pattern matches. Lines 4 and 5 illustrate printing the contents of the first match using an index notation. In this example, there will be only one match. If winpath had been a multiline string with multiple directory paths, then matcher would have had multiple matches. Line 6 shows accessing the first group within the match using a second index. Now that you have a match, you can start applying java.util.regex.Matcher methods. Line 7 is an example of replacing the first match with a new value. When you replace a match, it returns a new string.

Pattern Operator

The pattern operator (∼string) transforms a string into a pattern (java.util.regex.Pattern), which is a compiled regular expression. When you plan to use a regular expression over and over, consider creating a pattern. Reusing a pattern will give the application a performance boost.

Listing 2-26.  Creating and Using a Pattern

1. def saying = """Now is the time for all good men (and women) to come to the aid
2. of their country"""
3. def pattern = ∼/(w+en)/
4. def matcher = pattern.matcher(saying)
5. def count = matcher.getCount()
6. println "Matches = ${count}"
7. for(i in 0..<count) {
8. println matcher[i]
9. }

Here is the output:

Matches = 2
["men", "men"]
["women", "women"]

Lines 1 and 2 assign a famous quote to the saying variable. Line 3 defines a regular expression pattern that should find the words that end in en, such as men and women.

image Caution  Notice the space between the = and for the pattern operator in Listing 2-26. Without the space, it would be the find operator.

Line 4 applies the pattern to the saying and returns a matcher that contains the results.

Lines 5 and 6 print the number of matches. Lines 7–9 loop through and print the matches.

Common Uses of Regular Expressions

By now, you are starting to get an idea of how regular expressions work. Now let’s see how they can be applied in real-world scenarios. It is common for web applications to allow the user to enter personal information such as a telephone number. Two common tasks are to check that the phone number is a valid format and to parse the phone number into the individual parts. Listing 2-27 is an example of using the match operator to validate a phone number.

Listing 2-27.  Validating a Phone Number

def phoneValidation = /^[01]?s*[(.-]?(d{3})[).-]?s*(d{3})[.-](d{4})$/
assert '(800)555-1212' ==∼ phoneValidation
assert '1(800) 555-1212' ==∼ phoneValidation
assert '1-800-555-1212' ==∼ phoneValidation
assert '1.800.555.1212' ==∼ phoneValidation

In this example, you see the same phone number in four different valid formats. The regular expression to validate the phone number format is assigned to the variable phoneValidation. The match operator is used to validate the phone numbers by applying the regular expression to the phone number. If the phone number is valid, the match operator returns true.

Another common task is parsing a phone number so that the values can be put into a domain class. Listing 2-28 illustrates parsing the phone number into the individual parts and loading it in the domain class.

Listing 2-28.  Parsing the Phone Number

class Phone {
String areaCode
String exchange
String local
}
def phoneStr = '(800)555-1212'
def phoneRegex = ∼/^[01]?s*[(.-]?(d{3})[).-]?s*(d{3})[.-](d{4})$/
def matcher = phonePattern.matcher(phoneStr)
def phone = new Phone(
areaCode: matcher[0][1],
exchange: matcher[0][2],
local: matcher[0][3])
println "Original Phone Number: ${phoneStr}"
println """Parsed Phone Number
Area Code = ${phone.areaCode}
Exchange = ${phone.exchange}
Local = ${phone.local}"""

In this example, the Phone object, the phone number to parse (phone1), and the phone regular expression pattern (phoneRegex) are defined. Next, the phone pattern is applied to the phone number to be parsed. The pattern is defined with groups, which allows the regular expression to be used to parse the phone number into the individual parts. The construction of the Phone object illustrates accessing the individual parts using the second index. Lastly, we print out the phone number to prove that the parsing worked.

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. Groovy makes working with arrays a little easier, but you have the same limitations as with Java arrays.

Listing 2-29.  Creating and Using Arrays

1.  def stringArray = new String[3]
2.  println stringArray.size()
3.  stringArray[0] = "Chris"
4.  println stringArray // {"Chris", null, null}
5.  stringArray[1] = "Joseph"
6.  stringArray[2] = "Jim"
7.  println stringArray // {"Chris", "Joseph", "Jim"}
8.  println stringArray[1] // Joseph
9.  stringArray.each { println it} // Chris, Joseph, Jim
10. println stringArray[-1..-3] // ["Jim", "Joseph", "Chris"]

Line 1 creates a string array of size 3. Lines 3–8 use an index to access the array. Line9 illustrates using the each() method to iterate through the array. That deserves a second look. Yes, the each() method is available on the array, which is very convenient. The each() method is used to iterate through and apply the closure on every element. 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. Both the each() method and the it variable are discussed in detail in the Closures section of this chapter. Line 10 also shows something interesting—it uses a range, which will be discussed shortly, to access the array. In this case, the example goes one step further and shows accessing the array from left to right.

Lists

A Groovy list is an ordered collection of objects, just as in Java. It is an implementation of the java.util.List interface. In the course of building Grails applications, it is common to see lists returned from the controllers and services. Listing 2-30 illustrates creating a list and common usages.

Listing 2-30.  Creating and Using Lists

1.  def emptyList = []
2.  println emptyList.class.name // java.util.ArrayList
3.  println emptyList.size // 0
4.
5.  def list = ["Chris"] // List with one item in it
6.  // Add items to the list
7.  list.add "Joseph" // Notice the optional () missing
8.  list << "Jim" // Notice the overloaded left-shift operator
9.  println list.size // 3
10.
11. // Iterate over the list
12. list.each { println it } // Chris Joseph Jim
13.
14. // Access items in the list
15. println list[1] // Joseph // Indexed access
16. list[0] = "Christopher"
17. println list.get(0) // Christopher
18.
19. list.set(0, "Chris") // Set the 0 item to Chris
20. println list.get(0) // Chris
21.
22. list.remove 2
23. list-= "Joseph" // Overloaded - operator
24. list.each { println it } // Chris
25.
26. list.add "Joseph"
27. list+="Jim" // Overloaded + operator
28. list.each { println it } // Chris Joseph Jim
29. println list[-1] // Jim

On Line 1 of Listing 2-30, an empty list is created by assigning a property the value of [] . Line 2 prints out the list’s class name so that you can see that it is a java.util.ArrayList. Line 3 prints the list’s size, which is 0. Lines 5–9 create a list with an item already in it and show two ways to add items to the list.

Line 12 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. This is an example of using a closure as a parameter to a method. Lines 15–17 illustrate using an index to access a list. Lists are zero-based. Line 15 shows accessing the second item in the list. Line 16 shows using an index to assign position() the value “Christopher”. Line 17 accesses the list using the get()  method. Lines19–20 use the set() method to assign the first position in the list and then print it out. Lines 22–24 remove items from the list using the remove() method and the minus operator. Lines 26–28 add items to the list using the add() method and the plus operator. Line 29 is interesting—it uses the index value -1. Using a negative index value causes the list to be accessed in the opposite order, or from last to first.

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. By default, unless you specify otherwise, a Groovy map is a java.util.LinkedHashMap. If you are familiar with LinkedHashMap maps, you know that they are ordered by insert. If you need a map other than a LinkedHashMap, you can create any type of map by instantiating it; for example, def aTreeMap = new TreeMap(). In general, we encourage you to think of it as a regular map.

Listing 2-31 illustrates creating maps and common usages.

Listing 2-31.  Creating and Using Maps

1.  def emptyMap = [:]
2.  // map.class returns null, use getClass()
3.  println emptyMap.getClass().name //java.util.LinkedHashMap
4.  println emptyMap.size() // 0
5.
6.  def todos = ['a':'Write the map section', 'b':'Write the set section']
7.  println todos.size() // 2
8.  println todos["a"] // Write the map section
9.  println todos."a" // Write the map section
10. println todos.a // Write the map section
11. println todos.getAt("b") // Write the set section
12. println todos.get("b") // Write the set section
13. println todos.get("c", "unknown") // unknown, Notice "c" wasn't defined
14. // and now it is
15. println todos // ["a":"Write the map section", "b":"Write the set section",
16. // "c":"unknown"]
17.
18. todos.d = "Write the ranges section"
19. println todos.d // Write the ranges section
20. todos.put('e', 'Write the strings section')
21. println todos.e // Write the strings section
22. todos.putAt 'f', 'Write the closure section' // Notice () are optional
23. println todos.f // Write the closure section
24. todos[null] = 'Nothing Set' // Using null as a key
25. println todos[null] // Nothing set
26.
27. // Print each key/value pair on a separate Line
28. // Note: it is an implicit iterator
29. todos.each { println "Key: ${it.key}, Value: ${it.value}" }
30. // Print each key/value pair on a separate Line with index
31. todos.eachWithIndex { it, i -> println "${i} Key: ${it.key},Value: ${it.value}" }
33. // Print the value set
34. todos.values().each { println it }

In Line 1, an empty map is created by assigning a property the value [:]. Compare the creation of an empty list to the creation of an empty map. An empty list is created using the value []; an empty map is created using the value [:]. You can see from Line 2 that the map is implemented as a java.util.LinkedHashMap.

Line 6 illustrates defining a map with multiple entries. When using the square bracket notation, the colon separates the key from the value. Line 6 is [key1: value1,key2 : value2].

Lines 8–16 show several different techniques for accessing the map. The most interesting is Line 10. It shows using the key as a property to the map. You can use this technique to read an item from the map and put an item into the map.

Lines 18–25 show several different techniques for putting items into the map. You can see that they mirror the techniques used on lines 8–16.

Lines 29, 31, 32, and 34 illustrate iterating. Line 29 iterates over the map to print the key and value. Lines 31 and 32 iterate with an index. Line 34 iterates over the map values.

Ranges

A range is a list of sequential values. Logically, you can think of it as 1 through 10 or 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 implements java.lang.Comparable. The objects have next() and previous() methods to facilitate navigating through the range. This means that with a bit of work, it is possible to use your own Groovy objects within a range. Listing 2-32 illustrates some of things you can do with ranges.

Listing 2-32.  Creating and Using Ranges

1.  def numRange = 0..9
2.  println numRange.size() // 10
3.  numRange.each {print it} // 0123456789
4.  println ""
5.  println numRange.contains(5) // true
6.
7.  def alphaRange = 'a'..'z'
8.  println alphaRange.size() // 26
9.  println alphaRange[1] // b
10.
11. def exclusiveRange = 1..<10
12. println exclusiveRange.size() // 9
13. exclusiveRange.each {print it} // 123456789
14. println ""
15. println exclusiveRange.contains(10) // false
16.
17. def reverseRange = 9..0
18. reverseRange.each {print it} // 9876543210

Lines 1, 7, 11, and 17 illustrate defining ranges. Line 1 defines an inclusive range of numbers. Line 7 defines an inclusive range of lowercase letters. Line 11 defines an exclusive list of numbers. The range results in a range of numbers 1–9, excluding 10. Line 17creates a range in reverse order, 9 through 0.Frequently, ranges are used for iterating. In Listing 2-32, each() was used to iterate over the range. Listing 2-33 shows three ways you could use a range to iterate: one Java and two Groovy.

Listing 2-33.  Iterating with Ranges

1.  println "Java style for loop"
2.  for(int i=0;i<=9;i++) {
3.  println i
4.  }
5.
6.  println "Groovy style for loop"
7.  for (i in 0..9) {
8.  println i
9.  }
10.
11. println "Groovy range loop"
12. (0..9).each { i->
13. println i
14. }

Listing 2-33 starts off by showing a classic Java style for loop. Lines 7–9 are an example of the same loop using the Groovy style for loop. The for loop syntax is discussed in detail in the next section. Lines 12–14 illustrate yet another technique for looping, by using a range and the each() method. The each() method is used to iterate through and apply the closure on every element. 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. Both the each() method and it variable are discussed in detail in Closures section of this chapter.

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 Groovyset is a java.util.HashSet. If you need a set other than a HashSet, you can create any type of set by instantiating it; for example, def aTreeSet = new TreeSet(). In general, we encourage you to think of it as a regular set. Listing 2-34 illustrates creating sets and common usages.

Listing 2-34.  Creating and Using Sets

1.  def emptySet = [] as Set
2.  println emptySet.class.name // java.util.HashSet
3.  println emptySet.size() // 0
4.
5.  def list = ["Chris", "Chris" ]
6.  def set = ["Chris", "Chris" ] as Set
7.  println "List Size: ${list.size()} Set Size: ${set.size()}" // List Size: 2 Set
    Size: 1
8.  set.add "Joseph"
9.  set << "Jim"
10. println set.size() // 3
11. println set // ["Chris", "Jim", "Joseph"]
12.
13. // Iterate over the set
14. set.each { println it }
15.
16. set.remove 2
17. set-= "Joseph" // Overloaded - operator
18. set.each { println it } // Chris
19. set+= "Joseph"
20. set+= "Jim"
21. set.each { println it } // Chris Joseph Jim
22.
23. // Convert a set to a list
24. list = set as List
25. println list.class.name // java.util.ArrayList
26. println set.asList().class.name // java.util.ArrayList
27. println set.toList().class.name // java.util.ArrayList

Creating an empty set is similar to creating an empty list. The difference is the addition of the as Set clause. Lines 5–7 illustrate that a list allows duplicates and a set doesn’t. Lines 8–21 shouldn’t be any surprise. One of the important differences between a list and a set is that a list provides indexed-based access and a set doesn’t. Lines 24 and 26 show two different techniques to convert a set into a list.

Control Structure

Groovy provides the same control structures as in Java and makes them simpler. The control structures evaluate the expression and determine if the result of the expression is true or false, and on the basis of that alters the flow of control.

Groovy Truth

In Groovy, any expression can be evaluated, unlike in Java where only boolean variables and expressions can evaluate to true or false. In Groovy truth, null Object references evaluate to false. Non-empty collections, arrays, and maps, strings with non-zero length, and non-zero numbers will all evaluate to true. This is very helpful, especially with strings and collections, as illustrated in Listing 2-35.

Listing 2-35.  Null Check for Collections and Strings in Java

if (collection != null && !collection.isEmpty()) { ... } // collection
if (str != null && str.length() > 0) { ... }// string

Listing 2-36.  Null Check for Collections and Strings in Groovy

if (collection) { ... } // collection
if (str) { ... }// string

In Groovy, it is possible to provide a method for coercion to boolean in your own classes. Listing 2-37 illustrates  how Groovy offers the ability to coerce SomeClass instances to true or false, using the implementation of the booleanasBoolean() method.

Listing 2-37.  Using asBoolean() Method

class SomeClass{
boolean value
boolean asBoolean() { value }
}
assert new Test(value: true)
assert !new Test(value: false)

Logical Branching

Groovy has three conditionals: the if statement, the ternary operator, and the switch statement. The if statement and ternary operator are the same as in Java, though Groovy enhances the ternary operator with the Elvis operator. The Elvis operator is discussed in Chapter 3. The switch statement is more powerful in Groovy than in Java, in that the switch accepts any kind of object (unlike Java), as illustrated in Listing 2-38.

Listing 2-38.  Using switch

def x = 3.14
def result = ""

switch ( x ) {
    case "foo": result = "String"

    case [4, 5, 6 ]:
        result = "List"
        break

    case 12..30:
        result = "Range"
        break

    case Integer:
        result = "Integer"
        break

    case Number:
        result = "Number"
        break

    default:
        result = "Default"
}

assert result == "Number"

Looping

In addition to supporting Java for loops, Groovy also provides a much simpler for loop that works with any kind of array collection, as illustrated in Listing 2-39.

Listing 2-39.  Using the for Loop

for (i in 'Hello')Iterate over a string
    println i

for (i in 0..10)   //Iterate over a range
    println i

for (i in [1,2,3,4]) //Iterate over a list
    println i

authors = [1:'Vishal', 2:'Jim', 3: 'Chris', 4:'Joseph']

for (entry in map) //Iterate over a map
  println entry.key + ' ' + entry.value

Listing 2-39 shows the for loop for iterating over string, range, list, and map using the in operator as a shortcut for the contains method in a collection.

Exception Handling

Exception handling in Groovy is the same as in Java. Just as in Java, you can specify a try-catch-finally sequence of blocks, or just try-catch, or just try-finally. In addition to that, in Groovy, declarations of exceptions in the method signature are optional, even for checked exceptions, and a type declaration is optional in the catch expression.

In Groovy it is possible for try/catch/finally blocks to return a value when they are the last expression in a method or a closure. There is no need to explicitly use the return keyword inside these constructs, as long as they are the latest expression in the block of code. If an exception is thrown in the try block, the last expression in the catch block is returned instead. finally, blocks don’t return any value, as illustrated in Listing 2-40.

Listing 2-40.  Returning Value from try/catch/finally

def method(bool) {
    try {
        if (bool) throw new Exception("foo")
        1
    } catch(e) {
        2
    } finally {
        3
    }
}

assert method(false) == 1
assert method(true) == 2

In Groovy, it is also possible to define several exceptions to be catch and treated by the same catch block with the multi-catch block, as illustrated in Listing 2-41.

Listing 2-41.  Multi-catch Block

try{
   /* ... */
}catch(IOException | NullPointerException e) {
   /* one block to handle 2 exceptions*/
}

Methods

Listing 2-42 illustrates defining a method in Groovy the Java way.

Listing 2-42.  Defining aMethod the Java Way

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

Listing 2-43 illustrates defining the method using the Groovy idiom.

Listing 2-43.  Defining aMethod Using the Groovy Idiom

def hello(name) {
"Hello, ${name}"
}

The Groovy way of defining a method is a bit more compact. It takes advantage of a couple of Groovy’s optional features:

  • 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. By default, unless you specify otherwise, Groovy defaults all classes, properties, and methods to public access.

image Note  Strictly speaking, the Groovy version of the hello method (Listing 2-43) is not exactly like the Java version (Listing 2-42). The corresponding Java signature of the method would be: public Object hello (Object name). But, functionally, they are almost the same.

Closures

In Old Times on the Mississippi, Mark Twain wrote: “When I was a boy of 14, my father was so ignorant I could hardly stand to have the old man around. But when I got to be 21, I was astonished at how much the old man had learned in seven years.”

Functional programming is the old man who comes to the rescue when learning to write robust concurrent software. Functional programming gives you the right foundation to think about concurrency. The three keystones of this foundation are 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) and to that end we will give a brief introduction to functional programming. This introduction is by no means comprehensive, but sufficient enough to see Groovy in the functional light.

Groovy is not a pure functional language like Haskell, but we can still apply functional principles with it. 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, as input and output is essentially the ramification of side effects. One of the techniques to introduce side effects in a controlled manner is closure. A closure definition in Groovy follows the syntax:

{ [closure parameters ->] closure body}

Where [closure parameters->]  is an optional comma-delimited list of arguments, and closure body can be an expression as well as 0 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 2-44 illustrates this.

Listing 2-44.  Calling a Closure

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

As can be seen from the output, 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 2-45 illustrates the same closure as in Listing 2-44, but with the parameter.

Listing 2-45.  Closure with Parameter

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

Here is the output:

Hello world
Hello implicit world

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

Listing 2-46.  Parameters with Default Values

1. def sayHello= {str1, str2= " default world" -> println "${str1} ${str2}" }
2. sayHello("Hello", "world")
3. sayHello("Hello")
  • In Line 1, the sayHello closure takes two parameters, of which one parameter, str2, has a default value.
  • In 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 statement in the closure body, as illustrated in Listing 2-47, or as the value of the last executed statement if return is not explicitly specified, as illustrated in Listing 2-48.

Listing 2-47.  Using Return Keyword

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

Listing 2-48.  Return Keyword Optional

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

There are several ways to declare a closure. But before that, let’s look deeper into the mechanics of closure. To understand closure, 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 2-49 illustrates this.

Listing 2-49.  Free Variables

1. def myConst = 5
2. def incByConst = { num -> num + myConst }
3. println incByConst(10) // => 15

The runtime “closes over” the free variable (myConst in Listing 2-49) 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, several variables are defined that have special meaning:

it

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 that represents that one argument, illustrated in the Listing 2-50.

Listing 2-50.  Using it

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

Here is the output:

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.

this, owner, and delegate

The this refers to the instance of the enclosing class where a closure is defined. If the closure is defined within the scope of a script, the enclosing class is the script class. The owner is the enclosing object of the closure. The owner is similar to this except in the case of nested closures where the enclosing object is the outer closure. The delegate is by default the same as owner, but changeable; for example, in a builder or ExpandoMetaClass. Listing 2-51 illustrates these three implicit variables.

Listing 2-51.  Using this, owner, and delegate

1. class Class1{
2.   def closure = {
3.     println "---in closure---"
4.     println this.class.name
5.     println owner.class.name
6.     println delegate.class.name
7.     def nestedClosure = {
8.     println "---in nestedClosure---"
9.       println this.class.name
10.       println owner.class.name
11.       println delegate.class.name
12.     }
13.     nestedClosure()
14.    }
15. }
16.
17. def clos = new Class1().closure
18. clos()
19. println ""
20. println "===changing the delegate==="
21. clos.delegate = this
22. clos()
23. println ""
24.
25. def closure2 = {
26.    println "--- closure outside the class(in the script)---"
27.    println this.class.name
28.      println delegate.class.name
29.      println owner.class.name
30.
31. }
32.
33. closure2()
  • In Listing 2-51, the implicit variables this, owner, and delegate occur inside the outer closure from Line 4 to Line 6, inside the nested closure from Line 9 to Line 11, outside the class (closure2) from Line 27 to Line 29.
  • The this, owner, and delegate inside the outer closure from Line 4 to Line 6 refer to the class name; for example, Class1.
  • The this inside the nested closure from Line 9 to Line 11 refers to the class name (for example, Class1), and the owner and delegate refer to the closure class of the outer closure; for example, Class1$_closure1.
  • The this, owner, and delegate outside the class from Line 27 to Line 29 refer to the name of the script; for example, Hello.
  • In Line 21 we change the delegate of the closure (the outer closure in Class1) to the this, as we mentioned that the delegate is changeable.

Here is the output:

---in   closure---
Class1
Class1
Class1
---in   nestedClosure---
Class1
Class1$_closure1
Class1$_closure1
===changing  the  delegate===
---in   closure---
Class1
Class1
Hello
---in  nestedClosure---
Class1
Class1$_closure1
Class1$_closure1
---  closure   outside  the  class<in  the  script>---
Hello
Hello
Hello

Explicit Declaration of Closure

All closures defined in Groovy are essentially derived from the type Closure. Because groovy.lang is automatically imported, we can refer to Closure as a type within our code. This is explicit declaration of closure. The advantage of declaring closure explicitly is that a non-closure cannot be inadvertently assigned to such variable.

Listing 2-52.  Explicit Declaration of Closure

Closure clos = { 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 2-53 illustrates this.

Listing 2-53.  Reusing the Method as a Closure

1. def list = ["Vishal","Chris","Joseph","Jim"]
2. list.each { println it }
3. String printName(String name) {
4. println name
5. }
6. list.each(this.&printName)

Listing 2-53 creates a list of names and iterates through the list to print out the names. In Line 6, the method closure operator (.&) causes the method printName to be accessed as a closure.

Here is the output:

Vishal
Chris
Joseph
Jim
Vishal
Chris
Joseph
Jim

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.

Listing 2-54.  Passing a Closure As a Parameter

def list = ["Chris", "Joseph", "Jim"]
def sayHello = { println it }
list.each(sayHello)

Notice that sayHello is a property whose value is a closure. It is passed to the each() method so that as each() iterates over the list, the sayHello closure is invoked.

Closures and Collection

Lists, Maps, and Ranges include a number of methods (GDK methods) that have a closure parameter, which makes it effortless to iterate over the elements of the collection or range. We will discuss any, collect, each, every, and find methods.

any

The any method iterates through each element of a collection, checking whether a condition is valid for at least one element. The condition is provided by a closure. The signature of the any method is:

boolean any(Closure closure)

Listing 2-55.  Using the any Method

def anyElement= [1, 2, 3, 4].any {element -> element > 2}
assert anyElement == true

The any method in Listing 2-55 iterates through the list and returns true if any element is greater than 2.

collect

The collect method iterates through a collection, converts each element into a new value as specified in the closure and returns a new List. It has the signature:

List collect(Closure closure)

Listing 2-56.  Using the collect Method

def doubled = [1, 2, 3, 4].collect {element -> return 2*element}
assert doubled == [2,4,6,8]

each

The each method is used to iterate through a collection and apply the closure on every element. The signature of the each method is:

void each(Closure closure)

Listing 2-57.  Using the each Method

[1, 2, 3].each {println it}

Listing 2-50 prints the values 1, 2, 3 on separate lines.

Here is the output:

1
2
3

every

The every method is used to iterate through a collection to check if all the elements in the collection matches the condition specified in the closure. The signature of the every method is:

boolean every(Closure closure)

Listing 2-58.  Using the every Method

def allElements1 = [1, 2, 3, 4].every {element -> element > 1}
assert allElements1 == false

def allElements2 = [2, 3, 4, 5].every {element -> element > 1}
assert allElements2 == true

find

The find method finds the first value in a collection that matches some condition as specified in the closure. The signature of the find method is:

Object find(Closure closure)

Listing 2-59 illustrates using the find method to find the first element that is greater than 2.

Listing 2-59.  Using the find Method

def foundElement = [1, 2, 3, 4].find {element -> element > 2}
assert foundElement == 3

Closures as Map Keys and Values

It’s possible to put closures in a map, both as keys and values. You can use a closure as a key and as a value and call that closure as if it were a method on the map. However, when putting it into the map, you must escape it by enclosing it in parentheses. When accessing the value of the closure in the map, you must use get(key) or map[key], as map. Key will treat key as a string.

Listing 2-60.  Using Closure as Key and Value

1. key1 = { println "closure as key" }
2. map1 = [ (key1): 100 ]
3.
4. println  map1.get(key1)
5. println  map1[key1]
6.
7. map1 = [ key1: { println "closure as value" } ]
8. map1.key1()

The output is:

100
100

closure as value

  • In Line 1, a closure is used as a key: key1.
  • In Line 2, key1 is stored in the map and the value is 100.
  • Line 4 prints the value stored in the map.
  • Line 5 is another technique to retrieve the value.
  • In Line 7, a closure is used as a value.
  • Line 8 calls the closure stored as the value and prints “closure as value”.

Currying Closure

Currying is the technique of transforming a function that takes multiple arguments in such a way that it can be called as a chain of functions, each with a single argument. In Groovy, you can use the curry() method to form curried closures.

Listing 2-61.  Using Closure

1. def add= { x, y -> return x + y }
2. assert add(1,2) == 3
  • Line 1 defines an add closure that takes two parameters and adds them.
  • Line 2 replaces the formal parameter x with the value 1, replaces y with the value 2, and asserts that the sum is 3.

Now consider that instead of providing actual values to both formal parameters (x and y), we only provide a value to one of the parameters. The definition of the new closure with one actual value looks like this:

                 newAdd= { 1, y -> return 1 + y }

We just defined a new closure (newAdd) by providing actual value 1 to a formal parameter (x) of the closure add. This is what curry() method does for us; for example, we can define the closure newAdd by calling curry() on closure add, and provide the actual value 1 to one of the formal parameters, like so:

                 newAdd = add.curry(1)

The definition of this closure newAdd is still the same; for example, newAdd= {1,y -> 1+y}. We can fix the value of y in the same way by calling curry() on the closure newAdd; for example, newAdd.curry().

Listing 2-62.  Currying Closure

1. def add= { x, y -> return x + y }
2. def newAdd = closure.curry(1)
3. assert "${ newAdd(2)}" == 3

Closure Trampoline

As we discussed earlier, in functional programming, because of the immutability of variables, it is not possible to have loop counters that change through a loop on each pass. The pure functional way of implementing such loop counter is through recursion.

Recursion, in a large measure, plays a crucial role in functional programming. That said there are two latent problems associated with recursion: the performance penalty of repetitive function calls and the probability of stack overflow.  Performance penalty associated with repetitive function calls can be addressed with memorization, as discussed next.  Stack overflow can be avoided by converting the recursive calls into a loop called trampoline.

Listing 2-63.  Stack Overflow Error in Recursion

1. def factorial
2. factorial={n,BigInteger acc=1->
3.                 n == 1 ? acc:
4. factorial(n-1, n*acc)
5. }
6. factorial(1000)

A trampoline is a loop that works through a list of functions, calling each one in turn. In Groovy, a trampoline is formed by adding . trampoline() to a closure declaration, as illustrated in Listing 2-64.

Listing 2-64.  Using Trampoline

1. def factorial
2.
3. factorial={n, BigInteger acc=1->
4.
5. n == 1 ? acc:
6. factorial.trampoline(n-1, n*acc)
7. }.trampoline()
8.
9. factorial(1000)

Closure Memoization

Performance penalty associated with repetitive function calls in recursion can be addressed with memoization.

Memoization is a technique used to perform internal optimizations by caching previously computed values. Caching introduces side effects, in otherwise side effect free, pure functional programming, as the state of the cache is modified.

Listing 2-65.  Using Memoization

1. closure = {param1, param2 ->  sleep(100); param1 + param2 }
2.
3. memoizedClosure = closure.memoize()
4.
5. def testTime(param1, param2) {  begin = System.currentTimeMillis()
6.                                 memoizedClosure(param1, param2)
7.                                 timeElapsed = System.currentTimeMillis()
8.                                 println "param1 = $param1, param2 =
  $param2   time :${timeElapsed - begin } ms."

9. }
10.
11. testTime(1, 2)
12. testTime(3, 4)
13. testTime(1, 2)

The output is:

param1 = 1,  param2 = 2    time :153 ms.
param1 = 3,  param2 = 4    time :100 ms.
Param1 = 1,  param2 = 2    time :0 ms.

Listing 2-65  illustrates  memoization in action. In Line 3, closure is memoized. That is why the testTime closure call in Line 13 with the same parameters as in Line 11 takes 0 ms.

Operators

You use operators every day. They probably have become so familiar to you that you don’t even think of them anymore. Common operators include = for assignment, + to add two numbers, * to multiply two numbers, and ++ to increment a number. Of course, there are many more, but you get the idea.

Operator Overloading

Operator overloading has been around for some time, but absent from Java. Operator overloading was omitted from Java because of the bad experiences it brought with its usage in C++. Groovy embraces operator overloading and makes it easy to define and use. An overloaded operator executes a method on object. Groovy has predefined the relationship between the overloaded operator and the object method. Table 2-2 lists the Groovy operators and their corresponding methods. When an overloaded operator is encountered, the corresponding method is invoked.

Table 2-2. Operator Overloading

Operator Method
a + b a.plus(b)
a - b a.minus(b)
a * b a.multiply(b)
a ** b a.power(b)
a / b a.div(b)
a % b a.mod(b)
a | b a.or(b)
a & b a.and(b)
a ^ b a.xor(b)
a++ or ++a a.next()
a-- or --a a.previous()
a[b] a.getAt(b)
a[b] = c a.putAt(b, c)
a << b a.leftShift(b)
a >> b a.rightShift(b)
switch(a) { case(b) : } b.isCase(a)
∼a a.bitwiseNegate()
-a a.negative()
+a a.positive()

At first glance, you may not see the benefits of operator overloading. Groovy uses operator overloading to create shortcuts that make Java friendlier. For example, adding an object to a list in Java looks like this: myList.add(someObject). The corresponding Groovy way of adding an object to a list is myList << someObject. Operator overloading isn’t limited to the predefined instances that Groovy supplies; you can add operator overloading to your Groovy classes by implementing the corresponding method.

Specialized Operators

Groovy includes many of the standard operators found in other programming languages, as well as operators that are specific to Groovy that enable it to be so powerful.

Spread Operator

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

Listing 2-66.  Using the Spread Operator

1. def map = [1:"Vishal", 2:"Chris", 3:"Joseph", 4:"Jim"]
2. def keys = [1, 2, 3, 4]
3. def values = ["Vishal", "Chris", "Joseph", "Jim"]
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. An example of using the Java-style ternary operator is a == 1 ? "One" : "Not One" . If a is equal to 1, then “One” is returned; otherwise “Not One” is returned. It is literally a shorthand "if-then else."

As with most Java constructs, you can use the Java ternary operator in Groovy. In addition to the Java ternary operator, you can use an even shorter notation in Java: the Elvis operator. This can be very useful in defaulting values if they are not already set, meaning that they evaluate to null or false; that is,  b= a ?: 1 could be interpreted as:

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

Listing 2-67 illustrates using the Java ternary and Elvis operators in Groovy.

Listing 2-67.  Using the Elvis Operator

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

In both cases, if the user.firstName is null, then the firstName is set to “unknown”. The user.firstName portion of the Elvis operator example is known as the expression. If the expression evaluates to false or null, then the value after the : is returned. The two lines in the example are logically equivalent.

Safe Navigation/Dereference Operator

The safe navigation/dereference operator (?.) is used to avoid NullPointerExceptions, so it is incredibly handy. Consider the situation where you have a User object and you want a print the firstName. If the User object is null when you access the firstName property, you will get a NullPointerException.

Listing 2-68.  Using the Safe Navigation/Dereference Operator

class User {
    String firstName
    String lastName
    def printFullName = {
        println "${firstName} ${lastName}"
    }
}
User user
println user.firstName

The code in Listing 2-68 throws a NullPointerException. In Java, we add a null check this way:

if (user != null) {
    println "Java FirstName = ${user.firstName}"
}

Listing 2-69 illustrates adding the null-check using the safe-navigation/dereference operator in Groovy.

Listing 2-69.  Using the Safe Navigation/Dereference Operator

class User {
    String firstName
    String lastName
    def printFullName = {
        println "${firstName} ${lastName}"
    }
}
User user
println "Groovy FirstName = ${user?.firstName}"

Field Operator

In Chapter 1, you learned about properties on a class and how Groovy automatically supplies a getter. You also learned that in the event that special logic is required, you can provide your own getter. While not recommended because it is a major violation of encapsulation, Groovy provides a way to bypass the getter and access the underlying field directly.

Listing 2-70 shows an example of using the field operator (.@).

Listing 2-70.  Using the Field Operator

class Todo {
    String name
    def getName() {
        println "Getting Name"
        name
    }
}
def todo = new Todo(name: "Jim")
println todo.name
println todo.@name

Here is the output:

Getting Name
Jim
Jim

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

Earlier in the chapter, you learned about closures and how some of the Groovy functions accept a closure as input. But what if you would like to pass a method around in the same way that you can pass a closure? Groovy provides the method closure operator (.&) for just this scenario. The method closure operator allows the method to be accessed and passed around like a closure.

Listing 2-71.  Using the Method Closure Operator

def list = ["Chris","Joseph","Jim"]
// each takes a closure
list.each { println it }
String printName(String name) {
    println name
}
// & causes the method to be accessed as a closure
list.each(this.&printName)

Here is the output:

Chris
Joseph
Jim
Chris
Joseph
Jim

This example creates a list of names and iterates through the list to print out the names. You have seen this before. 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.

Now because this is a really simple example, you may be thinking, “Big deal.” Well actually it is, especially if you are building a domain-specific language (DSL), which you will learn more about in Chapter 3.The method really invokes System.out.println. How did the Groovy team get println to do that? The answer is that they used the method closure operator to assign System.out.println to a global property, as in def println = System.out.&println(). That is extremely powerful. Using the method closure operator, you are able to expose Java methods as closures.

Diamond Operator

In order to avoid the repetition of parameterized types, Groovy introduced the diamond operator. The parameterized types can be omitted and replaced with pointy brackets, which look like a diamond. Listing 2-72 shows a usual verbose way of defining a list.

Listing 2-72.  A Simple Groovy Script: Hello.groovy

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

Groovy allows us to use the diamond operator instead of a parameterized type to avoid repetition, as illustrated in Listing 2-73.

Listing 2-73.  Using the Diamond Operator

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

This means you can avoid specifying the <List<String>> on either side of the definition.

Summary

The focus of this chapter was Groovy language basics. The goal was to teach you enough Groovy to get you started with Grails. In this chapter, you created a simple program (script) and compared it to doing the same thing in Java. Then you learned how-to turn the script into a Groovy class, compile it, and run it using Java. Once you learned about Groovy scripts and classes, we took a quick look at the Groovy Shell and Groovy Console. The shell and console are handy for writing and testing simple programs. With some basic Groovy tooling under your belt, it was time to start taking a look at the Groovy language. Your journey into the Groovy language started with learning about Groovy’s support of strings, closures, and methods, and collections (lists, maps, sets, arrays, and ranges). Next, you had a high-level overview of Groovy’s regular expression support.

We covered the find (=∼), match (==∼), and pattern (∼string) operators. Lastly, you learned about operator overloading and specialized operators. They are a major source of Groovy’s power. This chapter is by no means a comprehensive study of Groovy. Groovy is a broad and deep topic. The goal here was to give you enough Groovy knowledge to start building an application and know where to look for more information. The next chapter will introduce you to more advanced Groovy topics.

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

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