These tutorials for those new to both Java and Groovy are in a sequence that builds on knowledge already presented. This tutorial therefore starts with the basics. We use code examples rather than lengthy explanations to present the features of Groovy, so you might miss things if you just skim. We don't (yet) explain what you would use the features for, but rely on your previous programming background for this.

The code snippets in these tutorials use comments to explain things:

//comment like this to end of line, ignoring */ and /* and ' and "
/*or comment like this, ignoring // and ' and " until: */
/*or comment over 
many lines, /*with no nesting*/

Groovy code can contain strings:

'A string can be within single quotes on one line...'
'''...or within triple single quotes
over many lines, ignoring // and */ and /* comment delimiters,...'''
"...or within double quotes..."
"""...or within triple double quotes
over many lines."""

Each line here does the same:

println 'hello, world' //the function 'println' prints a string then newline
print 'hello, world\n' //'print' doesn't print newline, but we can embed newlines ('\n' on Unix/Linux, '\r\n' on Windows)
println 'hello' + ', ' + 'world' // + joins strings together
print 'hello, '; println 'world' //use semi-colons to join two statements on one line
println( 'hello, world' ) //can put command parameter in parens, sometimes we might have to
def a= 'world'; println 'hello, ' + a //'def' to define a variable and give it a value
print 'hello, world'; println() //empty parens must be used for no-arg functions; here, prints a blank line
def b= 'hello', c= 'world'; println "$b, ${c}" //$ in print string captures variable's value

We can also assign integers and decimals to variables:

def g = 7, groovy = 10.2 //we can separate more than one defined variable by a comma
print g + ', ' + groovy + '\n' //prints: 7, 10.2
assert g + ', ' + groovy == '7, 10.2' //we can use assert statement and == operator to understand examples

We can use operators like + - * / and parentheses ( ) with numbers, following usual math grouping rules:

assert 4 * ( 2 + 3 ) - 6 == 14 //integers only
assert 2.5 + 7 == 9.5
assert 7 / 4 == 1.75 //decimal number or division converts expression to decimal

We can use the operators == > < >= <= != with numbers, the values true and false, the operators ! (not), && (and), and || (or), all with parentheses, to produce boolean expressions:

assert 2 > 3 == false
assert 7 <= 9
assert 7 != 2
assert true
assert ! false
assert 2 > 3 || 7 <= 9
assert ( 2 > 3 || 4 < 5 ) && 6 != 7

Variables are versatile:

def a
assert a == null //variables defined but not given a value have special value null
def b = 1
assert b == 1
b = 2
assert b == 2 //variables can be re-assigned to
b = 'cat'
assert b == 'cat' //they can be re-assigned different types/classes of data
b = null
assert b == null //they can be unassigned

All names in Groovy, including variable names, can contain any alphabetic character or the underscore, and contain any digit not in first position:

def abc= new Integer(4)
def a23c= new Integer(4)
def ab_c= new Integer(4)
def _abc= new Integer(4)

def ABC= new Integer(4)
assert abc == ABC //although their values are the same...
assert ! ABC ) //...the variables 'abc' and 'ABC' are different, the names being case-sensitive

/*these each produce compile errors when uncommented...
def abc //already defined
def a%c= 4 //not a valid name because it contains a symbol other than _
def 2bc= 4 //may not contain a digit in first position

All data in Groovy is built from “classes” and instances of them. Class names by convention begin with an uppercase character:

assert Byte.MAX_VALUE == 127 //a class can have attached variables, called 'fields'
assert Byte.parseByte('34') == 34 //a class can have attached functions, called 'methods'
def b= new Byte('34') //we can create an 'instance' of a class using the 'new' keyword
assert b.intValue() == 34 //each instance can also have attached fields and methods

We can inspect the class of any entity, such as numbers and strings, using the class field:

assert 4.class == Integer //the common types have both a short name...
assert 4.class == java.lang.Integer //...and a long name
assert 4.5.class == BigDecimal
assert 'hello, world'.class == String
def a= 7
assert a.class == Integer

There are many predefined classes in Groovy, but only the most common ones are always visible to Groovy code. Most need to be qualified with a “package” name, eg, 'java.text.DecimalFormat', or the package must be imported beforehand:

import java.text.*
assert new DecimalFormat( '#,#00.0#' ).format( 5.6789 ) == '05.68'

assert new java.text.DecimalFormat( '#,#00.0#' ).format( 5.6789 ) == '05.68'

If a line can be interpreted as a valid statement, it will be:

def i=
1 //because 'def i=' isn't a valid statement, the '1' is appended to the previous line

//a compile error when uncommented: 'def j' is valid, so is interpreted as a statement. Then the invalid '= 1' causes the error...
def j
= 1

def k \
= 1 //a backslash ensures a line is never interpreted as a standalone statement

Sometimes code in a script doesn't compile: we comment it out in our examples. Other code compiles but generates a "checked exception" which we can catch and handle.

  'moo'.toLong() //this will generate an exception
  assert false //this code should never be reached, so will always fail if executed
}catch(e){ assert e instanceof NumberFormatException } //we can check the exception type using 'instanceof'

We can use square brackets to represent both ordered lists and key mappings:

def list= [1, 2, 3]
list= [] //empty list
list= [1, 'b', false, 4.5 ] //mixed types of values OK
assert list[0] == 1 && list[1] == 'b' && ! list[2] && list[3] == 4.5 //we can refer to items individually by index

def map= [1:'a', 2:'b', 3:'c'] //map indicated with colon :
map= [:] //empty map
map= ['a': 1, 'b': 'c', 'groovy': 78.9, 12: true] //mixed types of values
assert map['a'] == 1 && map['b'] == 'c' && map['groovy'] == 78.9 && map[12] //we can refer to values individually by key

'each' tells the code following it to execute for each item in a list or map:

//for every item in list, assign to 'it' and execute the following code...
[ 2, -17, +987, 0 ].each{
  println it
//we can specify a different name for the argument other than the default...
[ 2, -17, +987, 0 ].each{ n -> 
  println n
//we can specify two or more arguments, as with this map...
[ 1: 3, 2: 6, 3: 9, 4: 12 ].each{ k, v-> 
  assert k * 3 == v

We can specify a list as a 'range', ie, by only the first and last items:

( 3..7 ).each{ println it } //prints numbers 3, 4, 5, 6, and 7
( 3..<7 ).each{ println it } //prints numbers 3, 4, 5, and 6, but excludes 7

Sometimes, we need to use a more efficient type of list known as an array, where the type of each element must be the same. Arrays can't be represented directly in the syntax, but we can convert a list to one easily:

def x= ['a', 'b', 'c'] as Integer[] //convert each item in list to an Integer
assert x[0] == 97 && x[1] == 98 && x[2] == 99 //access each element individually

We can choose between two execution options using the if-else-statement:

def a= 2
if( a < 5 ){
  println "a, being $a, is less than 5."
  assert false //this line should never execute

We can execute some code a certain number of times:

def i=0
10.times{ println i++ } //increment i by 1 after printing it

//another less declarative style of looping...
while( i > 0 ){
  println i-- //decrement i by 1 after printing it

We can enclose code in parentheses and execute it later. The enclosed code is called a closure:

def c= { def a= 5, b= 9; a * b }
assert c() == 45

[ { def a= 'ab'; a + 'bc' },
  { 'abbc' },
].each{ assert it() == 'abbc' }

We can spawn new threads from our main thread:

def i=0, j=0
def f= new File('TheOutput.txt') //create or overwrite this file
    if(i%1000 == 0) f<< 'S' //spawned thread
  if(j%1000 == 0) f<< 'M' //main thread

After, say, 5 seconds, abort the program then look at the file. On many computers, it'll show a roughly equal distribution of 'S' and 'M', but there'll be some irregularities showing that thread scheduling isn't perfectly timed.

The following tutorials are grouped into functional areas, beginning with numeric processing, and build up to the advanced features of Groovy.

Last edited Jan 28, 2011 at 12:45 PM by gavingrover, version 1


No comments yet.