Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: typo

Groovy uses both " and ' for strings. Either can be used. Using either type of string allows you to use strings with quotations easily.

Code Block

println "he said 'cheese' once"
println 'he said "cheese!" again'

...

Strings may be concatenated with "+". For example:

Code Block

#!/usr/bin/env groovy

a = "world"
print "hello " + a + "\n"

...

As an exception to this rule, a backslash at the end of a line disappears and joins the current line with the next.

Code Block

// this is a compile error
def foo = "hello

If you have a block of text which you wish to use but don't want to have to encode it all (e.g. if its a block of HTML or something) then you can use the """ syntax.

Code Block

def name = "James"
def text = """\
hello there ${name}
how are you today?
"""

assert text != null
println(text)

...

It is possible to use the another notation for String literals with the added benefit of not needing additional backslashes to escape special characters. That is especially handy with regular expressions or Windows file/directory path names.

Code Block

def s = /.*foo.*/
def dirname  = /^.*\//
def basename = /[Strings and GString^\/]+$/

The only escape that is supported in a slashy string is to use \/ to embed a slash into the string (Unicode characters (\uxxxx) are parsed before getting to the different String representations.). A consequence of this is that you can't have a backslash as the last character of a slashy string directly (or Groovy will think you are trying to escape the closing string terminator - and hence won't think you have terminated your string). Instead use: def bs = '\\\\'; def winpath=/C:\windows\system32$bs/ or def winpath=/C:\windows\system32\${}/.

...

A final gotcha: currently a slashy string can't be the left hand side (LHS) expression of an assert statement while you are eliminating the brackets, e.g.:

Code Block

assert 'ab' == 'a' + 'b'    // OK, no slashy string
assert 'a' + 'b' == /ab/    // OK, slashy string on RHS
assert (/ab/ == 'a' + 'b')  // brackets currently required if slashy string is on LHS

...

This can be seen with these two code snips, which you can cut and paste into groovyConsole:

Code Block

st = ["status":"test"]
sn = st
println sn
st.status = "tset"
println sn

Above both variables are references to the map.
If you do the same thing with Strings, the behavior is different:

Code Block

st = "test"
sn = st
println sn
st = "tset"
println sn

Here, sn and st point at the very same map object in memory in the first example, while in the second snippet, at the end, st points at a  different place in memory where there's the new immutable string.

GStrings

Strings that are declared inside double-quotes (i.e. either single double-quotes or triple double-quotes for multi-line strings) can contain arbitrary expressions inside them as shown above using the ${expression} syntax in a similar way to JSP EL, Velocity and Jexl. Any valid Groovy expression can be enclosed in the ${...} including method calls etc. GStrings are defined the same way as normal Strings would be created in Java. Here is a simple example involving a simple variable and an expression:

Code Block

foxtype = 'quick'
foxcolor = ['b', 'r', 'o', 'w', 'n']
println "The $foxtype ${foxcolor.join()} fox"
// => The quick brown fox

...

GString can involve lazy evaluation so it's not until the toString() method is invoked that the GString is evaluated. This lazy evaluation is useful for things like logging as it allows the calculation of the string, the calls to toString() on the values, and the concatenation of the different strings to be done lazily if at all. Here is an example that illustrates lazy evaluation:

Code Block

println new Date()
x = "It is currently ${ new Date() }"
assert x.values[0] instanceof Date
y = "It is currently ${ writer -> writer << new Date() }"
assert y.values[0] instanceof Closure
sleep 5000
println x
println y

which outputs the following:

No Format

Thu Apr 17 23:18:17 EST 2008
It is currently Thu Apr 17 23:18:17 EST 2008
It is currently Thu Apr 17 23:18:22 EST 2008

...

Warning
titleGStrings aren't Strings

GString and String are two distinct classes, and hence use of GString objects as keys for Map objects or comparisons involving GString objects, can produce unexpected results when combined with String objects since a GString and a String won't have the same hashCode nor will they be equal. There is no automatic coercion between the two types for comparisons or map keys, so it's sometimes necessary to explicitly invoke toString() on GString objects.

On the other hand GStrings can easily be made into Strings

Code Block

def s = "String "
def g = "GString created at ${new Date()}"
def x = s + g
assert s instanceof String
assert g instanceof GString
assert x instanceof String

Unexpected conversion to String can lead to problems when code is expecting a GString, as for methods in groovy.sql classes. That's a case were where explicit types can be beneficial:

Code Block

def s = "String "
def g = "GString created at ${new Date()}"
GString x = GString.EMPTY + s + g
assert s instanceof String
assert g instanceof GString
assert x instanceof GString
println x

...

  • For a closure with no parameter, Groovy calls the closure without parameter, and calls toString() on the result.
  • For a closure with one parameter, the parameter is actually a StringWriter to which you can append text in the body of your closure.
  • For a closure with more parameters, an exception will be thrown.

Illustration:

Code Block

def noParam = { -> println "I'm executed"; return "no param" }
def oneParam = { out -> println "Executed with a ${out.class}
parameter"; out << "one param" }

assert noParam.toString() != "no param"

println "${noParam} - ${oneParam}"

Result:

No Format

I'm executed
Executed with a class java.io.StringWriter parameter
no param - one param

The embedded closure could be used in a nested manner:

Code Block

def deepest = {-> "deepest"}
def deep = {-> "deeper and $deepest"}
println "how deep is deep? $deep"

// which is equivalent to:
println "how deep is deep? ${{-> "deeper and ${{-> "deepest"}}"}}" // for demonstrating it is a nested usage only

result:

No Format

how deep is deep? deeper and deepest
how deep is deep? deeper and deepest

...

The following example passes the test:

Code Block

aaa = '"bread","apple","egg"'
items = aaa.split(',')
assert items[1] == '"apple"'
items.each{ println "item: $it" }

...