~~SLIDESHOW~~
The slides and notes in this presentation are adapted from Groovy Programming (See Recommended Reading).
An index to the source code for all the examples in this lecture is available.
extern> http://www.cpjobling.org.uk/~eechris/at-m42/Examples/lecture02/example1.groovy
In Groovy, every datatype that you define, initialize and manipulate is an object: that is an instance of a class. A class is a specification for a data type that includes the fields (or attributes) and the operations (or methods) that can be performed on those fields.
In the example, class One
on line 2 declares a new class called One. Class One has one field, an integer (Integer
) named i which is declared and initialized to the value 1 on line 2. Class One has one method, named increment, which adds 1 to the current value of the field i
.
On line 10 we create an object of type One using the constructor def one = new one()
. The value returned by the right-hand-side of the assignment symbol =
is a reference to a new object in memory which contains storage for a single Integer object. Thus the variable one
on the left-hand-side is actually a reference to an object of type One
. We verify that this is the case on line 11 by asserting that the class of one, as a String, is “class One”
1)
On line 12 we assert that the value of the field one.i is equal to 1 and on line 13 we call the increment method on the one object after which the value of one.i becomes 2 (line 14). This demonstrates that one is an object of class One and that the “state” of the this object can be changed by calling its increment method2).
This may be confusing at the moment but it will become clearer when we talk about classes in more detail later.
0
, 1
, 26
, -42
, 0xFF
, 0177
-1.35
, 0.25
, 3.1415926
, 1e6
A literal is interpreted literally by the Groovy/Java compiler. In this context the term literal simply means the written value of a number.
For integer literals, all numbers are assumed to be decimal (base 10) unless
0x
is used, in which case the number following the prefix is assumed to hexadecimal base 16, or 0
is used, as in '0177', in which case the number is assumed to be octal or base 8. The octal and hexadecimal prefixes are useful for some applications where binary data (actual bits) needs to be manipulated.
Integer values are stored in an object of class java.lang.Integer
. By default, floating point literals are stored in an object of class java.lang.BigDecimal
because this has arbitrary precision. If you want, you can use single precision floating values (java.lang.Float
) or double precision (java.lang.Double
). In this case we add postfix f
(e.g. 1.234F
) to get a Float and d
(e.g. -0.123d
) for Double.
Like most computer languages. the letter e
(for exponent), in literals like 1.0e6
means “multiply by 10 raised-to-the-power-of the number to the right of the e
”. Thus 1.0e6
is 1×106.
Expression | Method call | Result |
---|---|---|
5 + 3 | 5.plus(3) | 8 |
5 - 3 | 5.minus(3) | 2 |
5 * 3 | 5.multiply(3) | 15 |
5 / 3 | 5.div(3) | 1.6666666667 |
5 % 3 | 5.mod(3) | 2 |
Although the normal infix operators are used in expressions, because integers are internally represented as objects of the Integer class, Groovy internally uses the method calls shown in the centre column to actually evaluate the expression. This has an important benefit which we will explore later. The only operator which you might be unfamiliar with is the modulus operator %
(mod()
) which returns the remainder of the object's value divided by the argument.
Both the infix form 5 / 3
and the object-method form 5.div(3)
are equivalent. in fact the groovy compiler turns the infix form into the object-method form when it compiles the expression. You can use either in your programs, thought clearly the infix form is more familiar and therefore easier to read and understand.
Expression | Method call | Result |
---|---|---|
5.0 + 3.0 | 5.0.plus(3.0) | 8.0 |
5.0 - 3.0 | 5.0.minus(3.0) | 2.0 |
5.0 * 3.0 | 5.0.multiply(3.0) | 15.0 |
5.0 / 3.0 | 5.0.div(3.0) | 1.6666666667 |
Division in Groovy will always return a floating point value. Thus the following are all equivalent:
13.0 / 5 13 / 5.0 13 / 5
If you are familiar with C or Java, this may surprise you! To get the C-like behaviour use intdiv
as in:
13.intdiv(5) // returns integer value 2
Mod is only defined for integers. if you try 5.0 % 3.0
you get:
Exception thrown: Cannot use mod() on this number type: java.math.BigDecimal with value: 5.0 java.lang.UnsupportedOperationException: Cannot use mod() on this number type: java.math.BigDecimal with value: 5.0
Expression | Method call | Result |
---|---|---|
5 + 3.2 | 5.plus(3.2) | 8.2 |
5.6 + 3 | 5.6.plus(3) | 8.6 |
5 - 3.2 | 5.minus(3.2) | 1.8 |
5.6 - 3 | 5.6.minus(3) | 2.6 |
5 * 3.2 | 5.multiply(3.2) | 16.0 |
5.6 * 3 | 5.6.multiply(3) | 16.8 |
5 * 3.2 | 5.div(3.2) | 1.5625 |
5.6 * 3 | 5.6.div(3) | 1.8666666667 |
With the exception of the modulus operator, Groovy's arithmetic operators can be applied to mixed combinations of integer and floats. In all cases, the integer terms are first converted to floating point values before the operators are applied.
Arithmetic operators
Category | Operators | Example | Associativity |
---|---|---|---|
Multiplicative | * / % | x * y | Left to right |
Additive | + - | x + y | Left to right |
Examples
2 + 3 * 4 = ? 2 * 3 / 4 = ?
The expression is evaluated left to right but multiplicative operators are evaluated first (highest priority) then the additive operators. In both cases the expression is evaluated left to right.
In the first example 3 * 4 is evaluated first;
3 * 4 => 12
Then 2 + 12
is evaluated yielding 14.
In the second example * and /
have the same priority so the expression is evaluate right to left:
2 * 3 => 6 6 / 4 => 1.25.
You should use parenthesis to change the order of evaluation:
(2 + 3) * 4 = 20 2 * (3/6) = 1.0
Other precedence relationships will be pointed out in the notes to the slides but they are summarized here.
The assignment operator
variable = expression
Examples
interest = principal * rate * time / 100 speed = distance / time totalMinutes = 60 * hours + minutes count = count + 1
The effect of the assignment operator (=
) is to evaluate the expression to its right, and assign the resulting value to the variable on the left.
in the examples;
principal
0 invested at a given rate
for a given period of time.count
.
In Groovy use the def
keyword:
def count = 0 // define and initialize count = count + 1 // increase current value by one
Variables have names by which they can be referenced. These names are known as identifiers. A Grrovy identifier must obey the following rule
An identifier is a case-sensitive combination of letters and digits, the first of which must be a letter. The underscore character (_
) is considered to be a letter. An identifier must not be a Groovy keyword.
Unary operators add one or delete one from the argument.
def x = 10 def y = x++ // x has value 11; y has value 10 def z = y-- // y now has value 9; z has value 10
def p = 20 def q = ++p // p has value 21; q has value 21 def r = --q // q now has value 20; r has value 20;
Note
value++
is shorthand for
value = value + 1
Similarly
value--
is shorthand for
value = value - 1
If the operator appears before the argument, it is known as a pre-increment or pre-decrement operator. Pre-incrementing a variable causes the value to be incremented before the result is used the expression in which it appears. Similarly pre-decrementing a variable causes the value to be decremented before the value is used in the expression. Post-incrementing a value causes the value to be used in the expression and then incremented.
The slide illustrates the differences.
The decrement operator x++
is implemented as x.next()
. Similarly the decrement operator y--
is implemented as y.previous()
Operator precedence: pre-increment/decrement are performed before the multiplicative operators. The post-increment/decrement operators before the pre-increment/decrement operators. Precedence for both are evaluated right-to-left in the expression.
Thus
def x = 1 def y = 3 + 1 * 4 / ++x
Evaluates to:
++x => 2 1 * 4 => 4 4 / 2 => 2 3 + 2 = 5
Exercise What are the values of p
and q
after the following expressions are evaluated?
def p = 2 def q = 4 - 2 / 4 * p++
[Answer p = 3; q = 3.0]
The execution of the assignment age = 25
creates a new Integer
object with the value 25. It then makes the variable reference the object as shown in the slide.
The linkage between a variable and the object is known as a reference. The variable is said to refer to that part of computer memory occupied by the object. Any use of the variable, such as in the expression age + 22
, uses this reference to obtain the object value associated with the variable.
In Groovy, variables are always linked to objects. hence the result of the second assignment is to have variable number
reference the same object as the variable age
. this is illustrated in this slide and is an example of sharing (or aliasing), for example, two variables referencing the same object.
If later in the code we assign a new value to the variable age
, then the effect is as illustrated in this slide. Here, we show that the age
variable now references a different object, while the number
variable continues to reference the object that was first referenced to age
If we now assign a new value to the number
variable, then the number 25 is no longer referenced by any variable. It cannot be used in the code (it is inaccessible) and is effectively garbage, namely an unreferenced object. In Groovy, a garbage collector will eventually sweep up the memory space taken by the object and recycle its memory space for other uses.
Control statements, such as if
and while
use conditional expressions which evaluate to a Boolean value true
or false
. Three types of operators provided:
Expression | Method call | Result |
---|---|---|
5 < 3 | 5.compareTo(3) < 0 | false |
5 <= 3 | 5.compareTo(3) <= 0 | false |
5 > 3 | 5.compareTo(3) > 0 | true |
5 >= 3 | 5.compareTo(3) >= 0 | true |
The relational operators are shown on this slide. All four are binary operators. Each takes two arithmetic expressions as operands and yields the booliean value either true
or false
. Both are instances of the class Boolean
. All of these operators are realised with the compareTo
method call. For example a < b
is implemented as a.compareTo(b)
. The method a.compareTo(b)
returns -1 if a is less than b, +1 if a is greater than b and 0 if a equals b. This method is also useful as the basis for sorting values.
extern> http://www.cpjobling.org.uk/~eechris/at-m42/Examples/lecture02/example2.groovy
Relational operators have lower precedence than arithmetic operators so index <= limit - 1
on line 9 is interpreted as index <= (limit - 1)
.
Expression | Method call | Result |
---|---|---|
5 == 3 | 5.equals(3) | false |
5 != 3 | ! 5.equals(3) | true |
5 <=> 3 | 5.compareTo(3) | +1 |
The equality operators ==
and '!=' are presented on this slide. Again they are binary operators and produce the boolean value true
or the boolean value false
. Both operators are implemented using the equals
method. The compareTo
operator is donated by <=>
and as the same precedence as the other two.
// Equality operators def forename = "Chris" def surname = "Jobling" assert forename == "Chris" assert surname != "Joblin" def age = 23 def number = 25 assert (age == number) == false
Once again these equality operators ultimately become method calls. For example, the condition forename == “Chris”
on line 4 is actually implemented as forename.equals(“Chris”)
. The method equals is programmed in the String
class to determine whether the two values are the same. Similarly, after the two assignments at lines 7 and 8, the condition on line 9 produces the value true
which satisfies the assertion. Again the method call age.equals(number)
is evaluated by the equals method defined in the class Integer
.
<html> <table class=“inline”> <tr><th>Literal</th><th>Description</th></tr> <tr><td>
'He said "Hello"!'
</td><td>Single quotes (with nested double quotes)</td></tr> <tr><td>
"He said 'Hello'!"
</td><td>Double quotes (with nested single quotes)</td></tr> <tr><td>
"""One two three"""
</td><td>Triple quotes</td></tr> <tr><td>
"""Spread<br /> over<br/> four<br/> lines"""
</td><td>Multi-line text using triple quotes</td></tr> </table> </html>
Groovy provides three ways to define a String
. For example, String
s can be enclosed in single quotes ('
), double quotes ("
), triple quotes ("""
). Furthermore, a triple quoted String
can span multiple lines. This slide summarises this types of String
literal.
def age = 25 'My age is ${age}' // My age is ${age} "My age is ${age}" // My age is 25 """My age is ${age}""" // My age is 25 "My age is \${age}" // My age is ${age}
A String
enclosed in single quotes is taken literally. The other two forms of String
are said to be interpreted. Any expression presented as ${expression}
within a double or triple quoted string is evaluated and the result is included as part of the String
. Some examples of interpreted String
s are shown in the slide.
Observe in line 1 how interpretation is not performed on single quoted strings. Also, observe how, in line 5, escaping the dollar sign with a backslash is required to turn off its use in String
interpretation. Normal practice is to use double-quoted strings only where interpretation is required and triple-quoted strings only where interpretation and multiple lines of text are required. Use single-quoted strings for all other purposes.
Interpreted String
s (which are also available in other languages like JavaScript, Perl, and Ruby) make it much easier to output results than it is in Java. To illustrate, consider the Java equivalent of line 3:
int age = 25; String s = "My age is " + age + ";
The equivalent of a triple-quoted multi-line String
in Java is even more “clunky”.
String mls = "Spread\nover\nfour\nlines";
In fact, Java strings are the equivalent of Groovy's single quoted strings. Groovy double-quoted and triple-quoted strings are much easier to read and understand.
extern> http://www.cpjobling.org.uk/~eechris/at-m42/Examples/lecture02/example4.groovy
Strings are represented internally as a sequence of characters. This
means that we can access an individual character by its position in
the String
. The position is given by an index. Positions can
specify either an individual character or a subset of
characters. Either way, a String
value is returned.String
indeces start at zero and end at one less that the String
length. Groovy also permits negative indices to count back from the
end of a String
(index -1 is the last character). Subsets of a
String
can also be expressed using slicing.
The slide shows some examples of indexing and slicing. Note how
slicing is denoted by 6..11
(line 5) and 6..<11
(line 6). This
notation is known as a range and will be discussed in the
next lecture. For now it suffices to say that
6..11
is the index range 6 to 11 inclusive. The range denoted by
1..<11
is range which excludes 11, that is 1 to 10.
extern> http://www.cpjobling.org.uk/~eechris/at-m42/Examples/lecture02/example5.groovy
The basic String
operations include the concatenation of two
strings, duplicating strings, and finding the length of a
String
. The minus
method (or the overloaded -
operator) removes the first occurrence of a substring. The method
count
determines the number of occurrences of a substring, while
contains
returns true
if a String
contains a substring.
Groovy strings and immutable; this means that they cannot be
changed in place. Each of the String
methods that actually appear
to change a String
actually return a new String
.
extern> http://www.cpjobling.org.uk/~eechris/at-m42/Examples/lecture02/example6.groovy
Note how the left-shift operator <<
overloads the leftShift
method. But be careful, it returns a StringBuffer
not a String
. This is why I ahd to use greeting.toString()
in lines 36 and 38 to convert the contents of the StringBuffer
back to a String
.
The method tokenize
splits a String
into a List
(see next lecture) of String
s. The first version of the method shown at line 61 uses a white space character as a separator. The second, at line 62, uses the String
parameter to partition it. The method split
splits a string around matches of the given regular expression (line 17), delivering an array of String
s.
extern> http://www.cpjobling.org.uk/~eechris/at-m42/Examples/lecture02/example7.groovy
Groovy supports methods for comparing String
s. As mentioned earlier, the operators are overloaded versions of named methods. Thus, we compare two String
objects using string1 == string2
, remembering that this is a convenience short cut for string1.equals(string2)
. Equally, the operator denoted as string1 <=> string2
is a convenience for string1.compareTo((string2)
. This method returns -1 if string1
is before string2
, +1 if string1
is after string2
, and 0 if the strings are equal. This might be used to sort strings.
String comparisons are lexicographic; therefore upper case letters precede lower case characters in the character set. hence, has shown in the last two examples in the slide (lines 7 and 8), 'chris' follows 'Chris' since 'C' precedes 'c'.
All characters in Groovy (and Java) String
s adopt the Unicode (www.unicode.org) character set and this makes programmes for the Java Platform relatively easy to internationalize.
A regular expression is a pattern that is used to find sub-strings in text.
String
method matches
method returns true
if the recipient String
matches the given regular expression pattern.assert 'abc'.matches(/abc/) == true assert 'abc'.matches(/bc/) == false
replaceAll
replaces all regular expression matches inside the String
with the replacement specified by the closure.assert 'HELLO'.replaceAll(/[A-Z]/) { ch -> ch.toLowerCase() } == 'hello'
extern> http://www.cpjobling.org.uk/~eechris/at-m42/Examples/lecture02/example8.groovy
Groovy supports regular expressions natively using the ~/regex/
expression where regex
represents the text of the regular expression – a specially formatted string.
In the example, a regular expression (an object of type java.util.regex.Pattern) is defined at line 2.
When the Groovy operator =~
appears as a predicate (expression returning a Boolean
) in expressions, the String
operand on the left is matched against the regular expression on the right. Each of the expressions shown on lines 5-6 is true which we can assert
as shown.
The stricter operator ==~ requires an exact match the whole of the String
on the left must match the regular expression on the right) as verified in line 10: 'cheesecake' ==~ /cheese/
is false
, so ! ('cheesecake' ==~ /cheese/)
is true
.
extern> http://www.cpjobling.org.uk/~eechris/at-m42/Examples/lecture02/example9.groovy
In a regular expression. two positional characters are used to denote the beginning and end of a line; caret (^
) and dollar ($
).
extern> http://www.cpjobling.org.uk/~eechris/at-m42/Examples/lecture02/example10.groovy
Regular expressions can also include quantifiers. The plus sign (+
) represents one or more times, applied to the preceding elements of the expression. The asterisk (*
) is used to represent zero or more occurrences. The question mark (?
) denotes zero or one occurrence. The meta character { and } is uses to match a specific number of the preceding character. All the examples in the slide yield true
.
extern> http://www.cpjobling.org.uk/~eechris/at-m42/Examples/lecture02/example11.groovy
In regular expression, the period symbol (.
) can represent any character. This is described as the wildcard character. Things get complicated, however, when we are required to match an actual period character. All the examples in the slide evaluate to true
.
extern> http://www.cpjobling.org.uk/~eechris/at-m42/Examples/lecture02/example12.groovy
A regular expression may include character classes. A set of characters can be given as a simple sequence of characters enclosed in the meta-characters [ and ] as in [aeiou]
. For letter and number ranges, you can use a dash separator as in [a-z]
or [a-mA-M]
. The complement of a character class is denoted by a leading caret with the square brackets as in [^a-z]
and represents all characters other than those specified. Each of the examples evaluates to true
.
extern> http://www.cpjobling.org.uk/~eechris/at-m42/Examples/lecture02/example13.groovy
Finally, we can group regular expression to compose more complex expressions. Groups are formed using the ( and ) meta-characters. Hence, “(ab)*
” is the regular expression for any number of occurrences of ab
. You can also use alternation (denoted by |
) to match a single regular expression from one of several regular expressions. Therefore “(a|b)
” describes any number of mixed a
or b
. The examples in the slide all evaluate to true
.
The basic building blocks for programming the Java platform in Groovy.